this repo has no description
at trunk 1086 lines 38 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "object-builtins.h" 3 4#include "gtest/gtest.h" 5 6#include "builtins.h" 7#include "frame.h" 8#include "ic.h" 9#include "runtime.h" 10#include "str-builtins.h" 11#include "test-utils.h" 12#include "type-builtins.h" 13 14namespace py { 15namespace testing { 16 17using NoneBuiltinsTest = RuntimeFixture; 18using ObjectBuiltinsTest = RuntimeFixture; 19 20TEST_F(ObjectBuiltinsTest, DunderEqWithIdenticalObjectsReturnsTrue) { 21 ASSERT_FALSE(runFromCStr(runtime_, R"( 22result = object.__eq__(None, None) 23)") 24 .isError()); 25 HandleScope scope(thread_); 26 Object result(&scope, mainModuleAt(runtime_, "result")); 27 EXPECT_EQ(*result, Bool::trueObj()); 28} 29 30TEST_F(ObjectBuiltinsTest, 31 DunderEqWithNonIdenticalObjectsReturnsNotImplemented) { 32 ASSERT_FALSE(runFromCStr(runtime_, R"( 33result = object.__eq__(object(), object()) 34)") 35 .isError()); 36 HandleScope scope(thread_); 37 Object result(&scope, mainModuleAt(runtime_, "result")); 38 EXPECT_TRUE(result.isNotImplementedType()); 39} 40 41TEST_F(ObjectBuiltinsTest, DunderGetattributeReturnsAttribute) { 42 HandleScope scope(thread_); 43 ASSERT_FALSE(runFromCStr(runtime_, R"( 44class C: pass 45i = C() 46i.foo = 79 47)") 48 .isError()); 49 Object i(&scope, mainModuleAt(runtime_, "i")); 50 Object name(&scope, runtime_->newStrFromCStr("foo")); 51 EXPECT_TRUE( 52 isIntEqualsWord(runBuiltin(METH(object, __getattribute__), i, name), 79)); 53} 54 55TEST_F(ObjectBuiltinsTest, DunderGetattributeWithNonStringNameRaisesTypeError) { 56 HandleScope scope(thread_); 57 Object object(&scope, NoneType::object()); 58 Object name(&scope, runtime_->newInt(0)); 59 EXPECT_TRUE(raisedWithStr( 60 runBuiltin(METH(object, __getattribute__), object, name), 61 LayoutId::kTypeError, "attribute name must be string, not 'int'")); 62} 63 64TEST_F(ObjectBuiltinsTest, 65 DunderGetattributeWithMissingAttributeRaisesAttributeError) { 66 HandleScope scope(thread_); 67 Object object(&scope, NoneType::object()); 68 Object name(&scope, runtime_->newStrFromCStr("xxx")); 69 EXPECT_TRUE(raisedWithStr( 70 runBuiltin(METH(object, __getattribute__), object, name), 71 LayoutId::kAttributeError, "'NoneType' object has no attribute 'xxx'")); 72} 73 74TEST_F(ObjectBuiltinsTest, DunderSetattrSetsValue) { 75 HandleScope scope(thread_); 76 ASSERT_FALSE(runFromCStr(runtime_, R"( 77class C: pass 78i = C() 79)") 80 .isError()); 81 Object i(&scope, mainModuleAt(runtime_, "i")); 82 Object name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 83 Object value(&scope, runtime_->newInt(42)); 84 EXPECT_TRUE( 85 runBuiltin(METH(object, __setattr__), i, name, value).isNoneType()); 86 ASSERT_TRUE(i.isInstance()); 87 Instance i_instance(&scope, *i); 88 EXPECT_TRUE( 89 isIntEqualsWord(instanceGetAttribute(thread_, i_instance, name), 42)); 90} 91 92TEST_F(ObjectBuiltinsTest, DunderSetattrWithNonStringNameRaisesTypeError) { 93 HandleScope scope(thread_); 94 Object object(&scope, NoneType::object()); 95 Object name(&scope, runtime_->newInt(0)); 96 Object value(&scope, runtime_->newInt(1)); 97 EXPECT_TRUE(raisedWithStr( 98 runBuiltin(METH(object, __setattr__), object, name, value), 99 LayoutId::kTypeError, "attribute name must be string, not 'int'")); 100} 101 102TEST_F(ObjectBuiltinsTest, DunderSetattrOnBuiltinTypeRaisesAttributeError) { 103 HandleScope scope(thread_); 104 Object object(&scope, NoneType::object()); 105 Object name(&scope, runtime_->newStrFromCStr("foo")); 106 Object value(&scope, runtime_->newInt(1)); 107 EXPECT_TRUE(raisedWithStr( 108 runBuiltin(METH(object, __setattr__), object, name, value), 109 LayoutId::kAttributeError, "'NoneType' object has no attribute 'foo'")); 110} 111 112TEST_F(ObjectBuiltinsTest, 113 DunderSizeofWithNonHeapObjectReturnsSizeofRawObject) { 114 HandleScope scope(thread_); 115 Object small_int(&scope, SmallInt::fromWord(6)); 116 Object result(&scope, runBuiltin(METH(object, __sizeof__), small_int)); 117 EXPECT_TRUE(isIntEqualsWord(*result, kPointerSize)); 118} 119 120TEST_F(ObjectBuiltinsTest, DunderSizeofWithLargeStrReturnsSizeofHeapObject) { 121 HandleScope scope(thread_); 122 HeapObject large_str(&scope, runtime_->createLargeStr(40)); 123 Object result(&scope, runBuiltin(METH(object, __sizeof__), large_str)); 124 EXPECT_TRUE(isIntEqualsWord(*result, large_str.size())); 125} 126 127TEST_F( 128 ObjectBuiltinsTest, 129 DunderNeWithSelfImplementingDunderEqReturningNotImplementedReturnsNotImplemented) { 130 ASSERT_FALSE(runFromCStr(runtime_, R"( 131class Foo(): 132 def __eq__(self, b): return NotImplemented 133 134result = object.__ne__(Foo(), None) 135)") 136 .isError()); 137 EXPECT_TRUE(mainModuleAt(runtime_, "result").isNotImplementedType()); 138} 139 140TEST_F(ObjectBuiltinsTest, 141 DunderNeWithSelfImplementingDunderEqReturningZeroReturnsTrue) { 142 ASSERT_FALSE(runFromCStr(runtime_, R"( 143class Foo(): 144 def __eq__(self, b): return 0 145 146result = object.__ne__(Foo(), None) 147)") 148 .isError()); 149 // 0 is converted to False, and flipped again for __ne__ from __eq__. 150 EXPECT_EQ(mainModuleAt(runtime_, "result"), Bool::trueObj()); 151} 152 153TEST_F(ObjectBuiltinsTest, 154 DunderNeWithSelfImplementingDunderEqReturningOneReturnsFalse) { 155 ASSERT_FALSE(runFromCStr(runtime_, R"( 156class Foo(): 157 def __eq__(self, b): return 1 158 159result = object.__ne__(Foo(), None) 160)") 161 .isError()); 162 // 1 is converted to True, and flipped again for __ne__ from __eq__. 163 EXPECT_EQ(mainModuleAt(runtime_, "result"), Bool::falseObj()); 164} 165 166TEST_F(ObjectBuiltinsTest, 167 DunderNeWithSelfImplementingDunderEqReturningFalseReturnsTrue) { 168 ASSERT_FALSE(runFromCStr(runtime_, R"( 169class Foo(): 170 def __eq__(self, b): return False 171 172result = object.__ne__(Foo(), None) 173)") 174 .isError()); 175 EXPECT_EQ(mainModuleAt(runtime_, "result"), Bool::trueObj()); 176} 177 178TEST_F(ObjectBuiltinsTest, 179 DunderNeWithSelfImplementingDunderEqReturningTrueReturnsFalse) { 180 ASSERT_FALSE(runFromCStr(runtime_, R"( 181class Foo(): 182 def __eq__(self, b): return True 183 184result = object.__ne__(Foo(), None) 185)") 186 .isError()); 187 EXPECT_EQ(mainModuleAt(runtime_, "result"), Bool::falseObj()); 188} 189 190TEST_F(ObjectBuiltinsTest, DunderStrReturnsDunderRepr) { 191 ASSERT_FALSE(runFromCStr(runtime_, R"( 192class Foo: 193 pass 194 195f = Foo() 196a = object.__str__(f) 197b = object.__repr__(f) 198)") 199 .isError()); 200 HandleScope scope(thread_); 201 Object a(&scope, mainModuleAt(runtime_, "a")); 202 Object b(&scope, mainModuleAt(runtime_, "b")); 203 EXPECT_TRUE(isStrEquals(a, b)); 204} 205 206TEST_F(ObjectBuiltinsTest, UserDefinedTypeInheritsDunderStr) { 207 ASSERT_FALSE(runFromCStr(runtime_, R"( 208class Foo: 209 pass 210 211f = Foo() 212a = object.__str__(f) 213b = f.__str__() 214)") 215 .isError()); 216 HandleScope scope(thread_); 217 Object a(&scope, mainModuleAt(runtime_, "a")); 218 Object b(&scope, mainModuleAt(runtime_, "b")); 219 EXPECT_TRUE(isStrEquals(a, b)); 220} 221 222TEST_F(ObjectBuiltinsTest, 223 DunderInitDoesNotRaiseIfNewIsDifferentButInitIsSame) { 224 ASSERT_FALSE(runFromCStr(runtime_, R"( 225class Foo: 226 def __new__(cls): 227 return object.__new__(cls) 228 229Foo.__init__(Foo(), 1) 230)") 231 .isError()); 232 // It doesn't matter what the output is, just that it doesn't throw a 233 // TypeError. 234} 235 236TEST_F(ObjectBuiltinsTest, DunderInitWithNonInstanceIsOk) { 237 ASSERT_FALSE(runFromCStr(runtime_, R"( 238object.__init__(object) 239)") 240 .isError()); 241 // It doesn't matter what the output is, just that it doesn't throw a 242 // TypeError. 243} 244 245TEST_F(ObjectBuiltinsTest, DunderInitWithNoArgsRaisesTypeError) { 246 // Passing no args to object.__init__ should throw a type error. 247 EXPECT_TRUE(raisedWithStr( 248 runFromCStr(runtime_, R"( 249object.__init__() 250)"), 251 LayoutId::kTypeError, 252 "'object.__init__' takes min 1 positional arguments but 0 given")); 253} 254 255TEST_F(ObjectBuiltinsTest, DunderInitWithArgsRaisesTypeError) { 256 // Passing extra args to object.__init__, without overwriting __new__, 257 // should throw a type error. 258 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"( 259class Foo: 260 pass 261 262Foo.__init__(Foo(), 1) 263)"), 264 LayoutId::kTypeError, 265 "object.__init__() takes no parameters")); 266} 267 268TEST_F(ObjectBuiltinsTest, DunderInitWithNewAndInitRaisesTypeError) { 269 // Passing extra args to object.__init__, and overwriting only __init__, 270 // should throw a type error. 271 EXPECT_TRUE(raisedWithStr(runFromCStr(runtime_, R"( 272class Foo: 273 def __init__(self): 274 object.__init__(self, 1) 275 276Foo() 277)"), 278 LayoutId::kTypeError, 279 "object.__init__() takes no parameters")); 280} 281 282TEST_F(NoneBuiltinsTest, NewReturnsNone) { 283 HandleScope scope(thread_); 284 Type type(&scope, runtime_->typeAt(LayoutId::kNoneType)); 285 EXPECT_TRUE(runBuiltin(METH(NoneType, __new__), type).isNoneType()); 286} 287 288TEST_F(NoneBuiltinsTest, NewWithExtraArgsRaisesTypeError) { 289 EXPECT_TRUE( 290 raised(runFromCStr(runtime_, "NoneType.__new__(NoneType, 1, 2, 3, 4, 5)"), 291 LayoutId::kTypeError)); 292} 293 294TEST_F(NoneBuiltinsTest, DunderReprIsBoundMethod) { 295 ASSERT_FALSE(runFromCStr(runtime_, "a = None.__repr__").isError()); 296 HandleScope scope(thread_); 297 Object a(&scope, mainModuleAt(runtime_, "a")); 298 EXPECT_TRUE(a.isBoundMethod()); 299} 300 301TEST_F(NoneBuiltinsTest, DunderReprReturnsNone) { 302 ASSERT_FALSE(runFromCStr(runtime_, "a = None.__repr__()").isError()); 303 HandleScope scope(thread_); 304 Object a(&scope, mainModuleAt(runtime_, "a")); 305 EXPECT_TRUE(isStrEqualsCStr(*a, "None")); 306} 307 308TEST_F(NoneBuiltinsTest, BuiltinBaseIsNone) { 309 HandleScope scope(thread_); 310 Type none_type(&scope, runtime_->typeAt(LayoutId::kNoneType)); 311 EXPECT_EQ(none_type.builtinBase(), LayoutId::kNoneType); 312} 313 314TEST_F(ObjectBuiltinsTest, 315 InstanceDelAttrWithHiddenAttributeReturnsErrorNotFound) { 316 HandleScope scope(thread_); 317 LayoutId layout_id = LayoutId::kUserWarning; 318 Object previous_layout(&scope, runtime_->layoutAt(layout_id)); 319 BuiltinAttribute attrs[] = { 320 {ID(__globals__), 0, AttributeFlags::kHidden}, 321 }; 322 Type type(&scope, addBuiltinType(thread_, ID(UserWarning), layout_id, 323 LayoutId::kObject, attrs, 324 /*size=*/kPointerSize, 325 /*basetype=*/true)); 326 Layout layout(&scope, type.instanceLayout()); 327 runtime_->layoutAtPut(layout_id, *layout); 328 Instance instance(&scope, runtime_->newInstance(layout)); 329 Str attribute_name(&scope, 330 Runtime::internStrFromCStr(thread_, "__globals__")); 331 EXPECT_TRUE( 332 instanceDelAttr(thread_, instance, attribute_name).isErrorNotFound()); 333 EXPECT_EQ(instance.layoutId(), layout.id()); 334 runtime_->layoutAtPut(layout_id, *previous_layout); 335} 336 337TEST_F(ObjectBuiltinsTest, 338 InstanceDelAttrWithInObjectAttributeDeletesAttribute) { 339 ASSERT_FALSE(runFromCStr(runtime_, R"( 340class C: 341 def __init__(self): 342 self.foo = 42 343instance = C() 344)") 345 .isError()); 346 HandleScope scope(thread_); 347 Instance instance(&scope, mainModuleAt(runtime_, "instance")); 348 Layout layout(&scope, runtime_->layoutOf(*instance)); 349 Object name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 350 AttributeInfo info; 351 ASSERT_TRUE(Runtime::layoutFindAttribute(*layout, name, &info)); 352 ASSERT_TRUE(info.isInObject()); 353 354 EXPECT_TRUE(instanceDelAttr(thread_, instance, name).isNoneType()); 355 EXPECT_TRUE(instanceGetAttribute(thread_, instance, name).isErrorNotFound()); 356 EXPECT_TRUE(instanceDelAttr(thread_, instance, name).isErrorNotFound()); 357} 358 359TEST_F(ObjectBuiltinsTest, 360 InstanceDelAttrWithTupleOverflowAttributeDeletesAttribute) { 361 ASSERT_FALSE(runFromCStr(runtime_, R"( 362class C: pass 363instance = C() 364instance.foo = 42 365)") 366 .isError()); 367 HandleScope scope(thread_); 368 Instance instance(&scope, mainModuleAt(runtime_, "instance")); 369 Layout layout(&scope, runtime_->layoutOf(*instance)); 370 Object name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 371 AttributeInfo info; 372 ASSERT_TRUE(Runtime::layoutFindAttribute(*layout, name, &info)); 373 ASSERT_TRUE(info.isOverflow()); 374 375 EXPECT_TRUE(instanceDelAttr(thread_, instance, name).isNoneType()); 376 EXPECT_TRUE(instanceGetAttribute(thread_, instance, name).isErrorNotFound()); 377 EXPECT_TRUE(instanceDelAttr(thread_, instance, name).isErrorNotFound()); 378} 379 380TEST_F(ObjectBuiltinsTest, 381 InstanceDelAttrWithNonexistentAttributeReturnsErrorNotFound) { 382 ASSERT_FALSE(runFromCStr(runtime_, R"( 383class C: pass 384instance = C() 385)") 386 .isError()); 387 HandleScope scope(thread_); 388 Instance instance(&scope, mainModuleAt(runtime_, "instance")); 389 Object name(&scope, Runtime::internStrFromCStr(thread_, "does_not_exist")); 390 EXPECT_TRUE(instanceDelAttr(thread_, instance, name).isErrorNotFound()); 391} 392 393TEST_F(ObjectBuiltinsTest, 394 InstanceDelAttrWithTupleOverflowAttributeKeepsOtherAttributes) { 395 ASSERT_FALSE(runFromCStr(runtime_, R"( 396class C: pass 397instance = C() 398instance.y = 2 399instance.z = 3 400)") 401 .isError()); 402 HandleScope scope(thread_); 403 Instance instance(&scope, mainModuleAt(runtime_, "instance")); 404 Object y(&scope, Runtime::internStrFromCStr(thread_, "y")); 405 Object result(&scope, instanceDelAttr(thread_, instance, y)); 406 EXPECT_TRUE(instanceGetAttribute(thread_, instance, y).isErrorNotFound()); 407 EXPECT_TRUE(result.isNoneType()); 408 Object z(&scope, Runtime::internStrFromCStr(thread_, "z")); 409 EXPECT_TRUE(isIntEqualsWord(instanceGetAttribute(thread_, instance, z), 3)); 410} 411 412TEST_F(ObjectBuiltinsTest, 413 InstanceDelAttrWithReadonlyAttributeRaisesAttributeError) { 414 HandleScope scope(thread_); 415 LayoutId layout_id = LayoutId::kUserWarning; 416 Object previous_layout(&scope, runtime_->layoutAt(layout_id)); 417 BuiltinAttribute attrs[] = { 418 {ID(__globals__), 0, AttributeFlags::kReadOnly}, 419 }; 420 Type type(&scope, addBuiltinType(thread_, ID(UserWarning), layout_id, 421 LayoutId::kObject, attrs, 422 /*size=*/kPointerSize, 423 /*basetype=*/true)); 424 Layout layout(&scope, type.instanceLayout()); 425 runtime_->layoutAtPut(layout_id, *layout); 426 Instance instance(&scope, runtime_->newInstance(layout)); 427 Str attribute_name(&scope, 428 Runtime::internStrFromCStr(thread_, "__globals__")); 429 EXPECT_TRUE(raisedWithStr(instanceDelAttr(thread_, instance, attribute_name), 430 LayoutId::kAttributeError, 431 "'__globals__' attribute is read-only")); 432 EXPECT_EQ(instance.layoutId(), layout.id()); 433 runtime_->layoutAtPut(layout_id, *previous_layout); 434} 435 436TEST_F(ObjectBuiltinsTest, 437 InstanceDelAttrWithDictOverflowAttributeDeletesAttribute) { 438 HandleScope scope(thread_); 439 ASSERT_FALSE(runFromCStr(runtime_, R"( 440def instance(): pass 441instance.foo = 42 442)") 443 .isError()); 444 Instance instance(&scope, mainModuleAt(runtime_, "instance")); 445 Layout layout(&scope, runtime_->layoutOf(*instance)); 446 ASSERT_TRUE(layout.hasDictOverflow()); 447 Object name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 448 AttributeInfo info; 449 ASSERT_FALSE(Runtime::layoutFindAttribute(*layout, name, &info)); 450 451 EXPECT_TRUE(instanceDelAttr(thread_, instance, name).isNoneType()); 452 EXPECT_TRUE(instanceGetAttribute(thread_, instance, name).isErrorNotFound()); 453 EXPECT_TRUE(instanceDelAttr(thread_, instance, name).isErrorNotFound()); 454} 455 456TEST_F( 457 ObjectBuiltinsTest, 458 InstanceDelAttrWithNonexistentAttributeDictOverflowReturnsErrorNotFound) { 459 HandleScope scope(thread_); 460 ASSERT_FALSE(runFromCStr(runtime_, R"( 461def instance(): pass 462)") 463 .isError()); 464 Instance instance(&scope, mainModuleAt(runtime_, "instance")); 465 Layout layout(&scope, runtime_->layoutOf(*instance)); 466 ASSERT_TRUE(layout.hasDictOverflow()); 467 Object name(&scope, Runtime::internStrFromCStr(thread_, "does_not_exist")); 468 EXPECT_TRUE(instanceDelAttr(thread_, instance, name).isErrorNotFound()); 469} 470 471TEST_F(ObjectBuiltinsTest, 472 InstanceGetAttributeWithInObjectAttributeReturnsValue) { 473 HandleScope scope(thread_); 474 ASSERT_FALSE(runFromCStr(runtime_, R"( 475class C: 476 def __init__(self): 477 self.foo = 42 478instance = C() 479)") 480 .isError()); 481 Instance instance(&scope, mainModuleAt(runtime_, "instance")); 482 Layout layout(&scope, runtime_->layoutOf(*instance)); 483 ASSERT_TRUE(layout.hasTupleOverflow()); 484 Object name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 485 AttributeInfo info; 486 ASSERT_TRUE(Runtime::layoutFindAttribute(*layout, name, &info)); 487 ASSERT_TRUE(info.isInObject()); 488 489 EXPECT_TRUE( 490 isIntEqualsWord(instanceGetAttribute(thread_, instance, name), 42)); 491} 492 493TEST_F(ObjectBuiltinsTest, 494 InstanceGetAttributeWithTupleOverflowAttributeReturnsValue) { 495 HandleScope scope(thread_); 496 ASSERT_FALSE(runFromCStr(runtime_, R"( 497class C: pass 498instance = C() 499instance.foo = 42 500)") 501 .isError()); 502 Instance instance(&scope, mainModuleAt(runtime_, "instance")); 503 Layout layout(&scope, runtime_->layoutOf(*instance)); 504 ASSERT_TRUE(layout.hasTupleOverflow()); 505 Object name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 506 AttributeInfo info; 507 ASSERT_TRUE(Runtime::layoutFindAttribute(*layout, name, &info)); 508 ASSERT_TRUE(info.isOverflow()); 509 510 EXPECT_TRUE( 511 isIntEqualsWord(instanceGetAttribute(thread_, instance, name), 42)); 512} 513 514TEST_F(ObjectBuiltinsTest, 515 InstanceGetAttributeWithDictOverflowAttributeReturnsValue) { 516 HandleScope scope(thread_); 517 ASSERT_FALSE(runFromCStr(runtime_, R"( 518def instance(): pass 519instance.foo = 42 520)") 521 .isError()); 522 Instance instance(&scope, mainModuleAt(runtime_, "instance")); 523 Layout layout(&scope, runtime_->layoutOf(*instance)); 524 ASSERT_TRUE(layout.hasDictOverflow()); 525 Object name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 526 AttributeInfo info; 527 ASSERT_FALSE(Runtime::layoutFindAttribute(*layout, name, &info)); 528 529 EXPECT_TRUE( 530 isIntEqualsWord(instanceGetAttribute(thread_, instance, name), 42)); 531} 532 533TEST_F(ObjectBuiltinsTest, 534 InstanceGetattributeWithHiddenAttributeReturnsErrorNotFound) { 535 HandleScope scope(thread_); 536 LayoutId layout_id = LayoutId::kUserWarning; 537 Object previous_layout(&scope, runtime_->layoutAt(layout_id)); 538 BuiltinAttribute attrs[] = { 539 {ID(__globals__), 0, AttributeFlags::kHidden}, 540 }; 541 Type type(&scope, addBuiltinType(thread_, ID(UserWarning), layout_id, 542 LayoutId::kObject, attrs, 543 /*size=*/kPointerSize, 544 /*basetype=*/true)); 545 Layout layout(&scope, type.instanceLayout()); 546 runtime_->layoutAtPut(layout_id, *layout); 547 Instance instance(&scope, runtime_->newInstance(layout)); 548 Str attribute_name(&scope, 549 Runtime::internStrFromCStr(thread_, "__globals__")); 550 EXPECT_TRUE(instanceGetAttribute(thread_, instance, attribute_name) 551 .isErrorNotFound()); 552 EXPECT_EQ(instance.layoutId(), layout.id()); 553 runtime_->layoutAtPut(layout_id, *previous_layout); 554} 555 556TEST_F( 557 ObjectBuiltinsTest, 558 InstanceGetAttributeWithNonExistentAttributeDictOverflowReturnsErrorNotFound) { 559 HandleScope scope(thread_); 560 ASSERT_FALSE(runFromCStr(runtime_, R"( 561def instance(): pass 562)") 563 .isError()); 564 Instance instance(&scope, mainModuleAt(runtime_, "instance")); 565 Layout layout(&scope, runtime_->layoutOf(*instance)); 566 ASSERT_TRUE(layout.hasDictOverflow()); 567 Object name(&scope, Runtime::internStrFromCStr(thread_, "does_not_exist")); 568 EXPECT_TRUE(instanceGetAttribute(thread_, instance, name).isErrorNotFound()); 569} 570 571TEST_F(ObjectBuiltinsTest, InstanceSetAttrSetsInObjectAttribute) { 572 HandleScope scope(thread_); 573 ASSERT_FALSE(runFromCStr(runtime_, R"( 574class C: 575 def __init__(self, set_value): 576 if set_value: 577 self.foo = 42 578instance = C(False) 579)") 580 .isError()); 581 Instance instance(&scope, mainModuleAt(runtime_, "instance")); 582 Object name(&scope, Runtime::internStrFromCStr(thread_, "bar")); 583 Object value(&scope, runtime_->newInt(-7)); 584 EXPECT_TRUE(instanceSetAttr(thread_, instance, name, value).isNoneType()); 585 586 Layout layout(&scope, runtime_->layoutOf(*instance)); 587 AttributeInfo info; 588 ASSERT_TRUE(Runtime::layoutFindAttribute(*layout, name, &info)); 589 ASSERT_TRUE(info.isInObject()); 590 591 EXPECT_TRUE( 592 isIntEqualsWord(instanceGetAttribute(thread_, instance, name), -7)); 593} 594 595TEST_F(ObjectBuiltinsTest, InstanceSetAttrSetsNewTupleOverflowAttribute) { 596 HandleScope scope(thread_); 597 ASSERT_FALSE(runFromCStr(runtime_, R"( 598class C: pass 599instance = C() 600)") 601 .isError()); 602 Instance instance(&scope, mainModuleAt(runtime_, "instance")); 603 Object name(&scope, Runtime::internStrFromCStr(thread_, "bar")); 604 Object value(&scope, runtime_->newInt(-14)); 605 EXPECT_TRUE(instanceSetAttr(thread_, instance, name, value).isNoneType()); 606 607 Layout layout(&scope, runtime_->layoutOf(*instance)); 608 Tuple overflow(&scope, instance.instanceVariableAt(layout.overflowOffset())); 609 EXPECT_EQ(overflow.length(), 1); 610 611 AttributeInfo info; 612 ASSERT_TRUE(Runtime::layoutFindAttribute(*layout, name, &info)); 613 ASSERT_TRUE(info.isOverflow()); 614 615 EXPECT_TRUE( 616 isIntEqualsWord(instanceGetAttribute(thread_, instance, name), -14)); 617} 618 619TEST_F(ObjectBuiltinsTest, InstanceSetAttrSetsExistingTupleOverflowAttribute) { 620 HandleScope scope(thread_); 621 ASSERT_FALSE(runFromCStr(runtime_, R"( 622class C: pass 623instance = C() 624instance.bar = 5000 625)") 626 .isError()); 627 Instance instance(&scope, mainModuleAt(runtime_, "instance")); 628 Layout layout(&scope, runtime_->layoutOf(*instance)); 629 Tuple overflow(&scope, instance.instanceVariableAt(layout.overflowOffset())); 630 ASSERT_EQ(overflow.length(), 1); 631 632 Object name(&scope, Runtime::internStrFromCStr(thread_, "bar")); 633 Object value(&scope, runtime_->newInt(-14)); 634 EXPECT_TRUE(instanceSetAttr(thread_, instance, name, value).isNoneType()); 635 ASSERT_EQ(overflow.length(), 1); 636 637 AttributeInfo info; 638 ASSERT_TRUE(Runtime::layoutFindAttribute(*layout, name, &info)); 639 ASSERT_TRUE(info.isOverflow()); 640 641 EXPECT_TRUE( 642 isIntEqualsWord(instanceGetAttribute(thread_, instance, name), -14)); 643} 644 645TEST_F(ObjectBuiltinsTest, InstanceSetAttrSetsDictOverflowAttribute) { 646 HandleScope scope(thread_); 647 ASSERT_FALSE(runFromCStr(runtime_, R"( 648def instance(): pass 649)") 650 .isError()); 651 Instance instance(&scope, mainModuleAt(runtime_, "instance")); 652 Object name(&scope, Runtime::internStrFromCStr(thread_, "bar")); 653 Object value(&scope, runtime_->newInt(4711)); 654 Layout layout(&scope, runtime_->layoutOf(*instance)); 655 ASSERT_TRUE(layout.hasDictOverflow()); 656 657 EXPECT_TRUE(instanceSetAttr(thread_, instance, name, value).isNoneType()); 658 EXPECT_EQ(instance.layoutId(), layout.id()); 659 660 AttributeInfo info; 661 ASSERT_FALSE(Runtime::layoutFindAttribute(*layout, name, &info)); 662 EXPECT_TRUE( 663 isIntEqualsWord(instanceGetAttribute(thread_, instance, name), 4711)); 664} 665 666TEST_F(ObjectBuiltinsTest, 667 InstanceSetAttrWithHiddenAttributeRaisesAttributeError) { 668 HandleScope scope(thread_); 669 LayoutId layout_id = LayoutId::kUserWarning; 670 Object previous_layout(&scope, runtime_->layoutAt(layout_id)); 671 BuiltinAttribute attrs[] = { 672 {ID(__globals__), 0, AttributeFlags::kHidden}, 673 }; 674 Type type(&scope, addBuiltinType(thread_, ID(UserWarning), layout_id, 675 LayoutId::kObject, attrs, 676 /*size=*/kPointerSize, 677 /*basetype=*/true)); 678 Layout layout(&scope, type.instanceLayout()); 679 runtime_->layoutAtPut(layout_id, *layout); 680 Instance instance(&scope, runtime_->newInstance(layout)); 681 Str attribute_name(&scope, 682 Runtime::internStrFromCStr(thread_, "__globals__")); 683 Object value(&scope, runtime_->newInt(4711)); 684 EXPECT_TRUE( 685 raisedWithStr(instanceSetAttr(thread_, instance, attribute_name, value), 686 LayoutId::kAttributeError, 687 "'UserWarning.__globals__' attribute cannot be set")); 688 EXPECT_EQ(instance.layoutId(), layout.id()); 689 runtime_->layoutAtPut(layout_id, *previous_layout); 690} 691 692TEST_F(ObjectBuiltinsTest, ObjectGetAttributeReturnsInstanceValue) { 693 HandleScope scope(thread_); 694 ASSERT_FALSE(runFromCStr(runtime_, R"( 695class C: pass 696c = C() 697c.__hash__ = 42 698)") 699 .isError()); 700 Object c(&scope, mainModuleAt(runtime_, "c")); 701 Object name(&scope, Runtime::internStrFromCStr(thread_, "__hash__")); 702 EXPECT_TRUE(isIntEqualsWord(objectGetAttribute(thread_, c, name), 42)); 703} 704 705TEST_F(ObjectBuiltinsTest, ObjectGetAttributeReturnsTypeValue) { 706 HandleScope scope(thread_); 707 ASSERT_FALSE(runFromCStr(runtime_, R"( 708class C: 709 x = -11 710c = C() 711)") 712 .isError()); 713 Object c(&scope, mainModuleAt(runtime_, "c")); 714 Object name(&scope, Runtime::internStrFromCStr(thread_, "x")); 715 EXPECT_TRUE(isIntEqualsWord(objectGetAttribute(thread_, c, name), -11)); 716} 717 718TEST_F(ObjectBuiltinsTest, ObjectGetAttributeWithNonExistentNameReturnsError) { 719 HandleScope scope(thread_); 720 ASSERT_FALSE(runFromCStr(runtime_, R"( 721class C: pass 722c = C() 723)") 724 .isError()); 725 Object c(&scope, mainModuleAt(runtime_, "c")); 726 Object name(&scope, Runtime::internStrFromCStr(thread_, "xxx")); 727 EXPECT_TRUE(objectGetAttribute(thread_, c, name).isError()); 728 EXPECT_FALSE(thread_->hasPendingException()); 729} 730 731TEST_F(ObjectBuiltinsTest, ObjectGetAttributeCallsDunderGetOnDataDescriptor) { 732 HandleScope scope(thread_); 733 ASSERT_FALSE(runFromCStr(runtime_, R"( 734class D: 735 def __set__(self, instance, value): pass 736 def __get__(self, instance, owner): return 42 737class A: 738 foo = D() 739a = A() 740)") 741 .isError()); 742 Object a(&scope, mainModuleAt(runtime_, "a")); 743 Object name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 744 EXPECT_TRUE(isIntEqualsWord(objectGetAttribute(thread_, a, name), 42)); 745} 746 747TEST_F(ObjectBuiltinsTest, 748 ObjectGetAttributeCallsDunderGetOnNonDataDescriptor) { 749 HandleScope scope(thread_); 750 ASSERT_FALSE(runFromCStr(runtime_, R"( 751class D: 752 def __get__(self, instance, owner): return 42 753class A: 754 foo = D() 755a = A() 756)") 757 .isError()); 758 Object a(&scope, mainModuleAt(runtime_, "a")); 759 Object name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 760 EXPECT_TRUE(isIntEqualsWord(objectGetAttribute(thread_, a, name), 42)); 761} 762 763TEST_F(ObjectBuiltinsTest, 764 ObjectGetAttributePrefersDataDescriptorOverInstanceAttr) { 765 HandleScope scope(thread_); 766 ASSERT_FALSE(runFromCStr(runtime_, R"( 767class D: 768 def __set__(self, instance, value): pass 769 def __get__(self, instance, owner): return 42 770class A: 771 pass 772a = A() 773a.foo = 12 774A.foo = D() 775)") 776 .isError()); 777 Object a(&scope, mainModuleAt(runtime_, "a")); 778 Object name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 779 EXPECT_TRUE(isIntEqualsWord(objectGetAttribute(thread_, a, name), 42)); 780} 781 782TEST_F(ObjectBuiltinsTest, 783 ObjectGetAttributePrefersInstanceAttrOverNonDataDescriptor) { 784 HandleScope scope(thread_); 785 ASSERT_FALSE(runFromCStr(runtime_, R"( 786class D: 787 def __get__(self, instance, owner): return 42 788class A: 789 foo = D() 790a = A() 791a.foo = 12 792)") 793 .isError()); 794 Object a(&scope, mainModuleAt(runtime_, "a")); 795 Object name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 796 EXPECT_TRUE(isIntEqualsWord(objectGetAttribute(thread_, a, name), 12)); 797} 798 799TEST_F(ObjectBuiltinsTest, ObjectGetAttributePropagatesDunderGetException) { 800 HandleScope scope(thread_); 801 ASSERT_FALSE(runFromCStr(runtime_, R"( 802class D: 803 def __set__(self, instance, value): pass 804 def __get__(self, instance, owner): raise UserWarning() 805class A: 806 foo = D() 807a = A() 808)") 809 .isError()); 810 Object a(&scope, mainModuleAt(runtime_, "a")); 811 Object name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 812 EXPECT_TRUE( 813 raised(objectGetAttribute(thread_, a, name), LayoutId::kUserWarning)); 814} 815 816TEST_F(ObjectBuiltinsTest, 817 ObjectGetAttributeOnNoneNonDataDescriptorReturnsBoundMethod) { 818 HandleScope scope(thread_); 819 Object none(&scope, NoneType::object()); 820 Object name(&scope, Runtime::internStrFromCStr(thread_, "__repr__")); 821 EXPECT_TRUE(objectGetAttribute(thread_, none, name).isBoundMethod()); 822} 823 824TEST_F(ObjectBuiltinsTest, 825 ObjectGetAttributeSetLocationReturnsBoundMethodAndCachesFunction) { 826 HandleScope scope(thread_); 827 ASSERT_FALSE(runFromCStr(runtime_, R"( 828class C: 829 def foo(): 830 pass 831foo = C.foo 832i = C() 833)") 834 .isError()); 835 Object foo(&scope, mainModuleAt(runtime_, "foo")); 836 Object i(&scope, mainModuleAt(runtime_, "i")); 837 838 Object name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 839 Object to_cache(&scope, NoneType::object()); 840 LoadAttrKind kind = LoadAttrKind::kUnknown; 841 Object result_obj(&scope, objectGetAttributeSetLocation(thread_, i, name, 842 &to_cache, &kind)); 843 ASSERT_TRUE(result_obj.isBoundMethod()); 844 BoundMethod result(&scope, *result_obj); 845 EXPECT_EQ(result.function(), foo); 846 EXPECT_EQ(result.self(), i); 847 EXPECT_EQ(to_cache, foo); 848 EXPECT_EQ(kind, LoadAttrKind::kInstanceFunction); 849 850 Object load_cached_result_obj( 851 &scope, Interpreter::loadAttrWithLocation(thread_, *i, *to_cache)); 852 ASSERT_TRUE(load_cached_result_obj.isBoundMethod()); 853 BoundMethod load_cached_result(&scope, *load_cached_result_obj); 854 EXPECT_EQ(load_cached_result.function(), foo); 855 EXPECT_EQ(load_cached_result.self(), i); 856} 857 858TEST_F(ObjectBuiltinsTest, 859 ObjectGetAttributeSetLocationReturnsInstanceVariableAndCachesOffset) { 860 HandleScope scope(thread_); 861 ASSERT_FALSE(runFromCStr(runtime_, R"( 862class C: 863 def __init__(self): 864 self.foo = 42 865i = C() 866)") 867 .isError()); 868 Object i(&scope, mainModuleAt(runtime_, "i")); 869 870 Layout layout(&scope, runtime_->layoutOf(*i)); 871 Object name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 872 AttributeInfo info; 873 ASSERT_TRUE(Runtime::layoutFindAttribute(*layout, name, &info)); 874 ASSERT_TRUE(info.isInObject()); 875 876 Object to_cache(&scope, NoneType::object()); 877 LoadAttrKind kind = LoadAttrKind::kUnknown; 878 EXPECT_TRUE(isIntEqualsWord( 879 objectGetAttributeSetLocation(thread_, i, name, &to_cache, &kind), 42)); 880 EXPECT_TRUE(isIntEqualsWord(*to_cache, info.offset())); 881 EXPECT_EQ(kind, LoadAttrKind::kInstanceOffset); 882 883 EXPECT_TRUE(isIntEqualsWord( 884 Interpreter::loadAttrWithLocation(thread_, *i, *to_cache), 42)); 885} 886 887TEST_F( 888 ObjectBuiltinsTest, 889 ObjectGetAttributeSetLocationReturnsInstanceVariableAndCachesNegativeOffset) { 890 HandleScope scope(thread_); 891 ASSERT_FALSE(runFromCStr(runtime_, R"( 892class C: 893 pass 894i = C() 895i.foo = 17 896)") 897 .isError()); 898 Object i(&scope, mainModuleAt(runtime_, "i")); 899 900 Layout layout(&scope, runtime_->layoutOf(*i)); 901 Object name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 902 AttributeInfo info; 903 ASSERT_TRUE(Runtime::layoutFindAttribute(*layout, name, &info)); 904 ASSERT_TRUE(info.isOverflow()); 905 906 Object to_cache(&scope, NoneType::object()); 907 LoadAttrKind kind = LoadAttrKind::kUnknown; 908 EXPECT_TRUE(isIntEqualsWord( 909 objectGetAttributeSetLocation(thread_, i, name, &to_cache, &kind), 17)); 910 EXPECT_TRUE(isIntEqualsWord(*to_cache, -info.offset() - 1)); 911 912 EXPECT_TRUE(isIntEqualsWord( 913 Interpreter::loadAttrWithLocation(thread_, *i, *to_cache), 17)); 914} 915 916TEST_F(ObjectBuiltinsTest, 917 ObjectGetAttributeSetLocationRaisesAttributeErrorAndDoesNotSetLocation) { 918 HandleScope scope(thread_); 919 ASSERT_FALSE(runFromCStr(runtime_, R"( 920class C: 921 pass 922i = C() 923)") 924 .isError()); 925 Object i(&scope, mainModuleAt(runtime_, "i")); 926 927 Object name(&scope, Runtime::internStrFromCStr(thread_, "xxx")); 928 Object to_cache(&scope, NoneType::object()); 929 LoadAttrKind kind = LoadAttrKind::kUnknown; 930 EXPECT_TRUE(objectGetAttributeSetLocation(thread_, i, name, &to_cache, &kind) 931 .isError()); 932 EXPECT_TRUE(to_cache.isNoneType()); 933 EXPECT_EQ(kind, LoadAttrKind::kUnknown); 934} 935 936TEST_F(ObjectBuiltinsTest, ObjectGetItemCallsTypeObjectDunderClassItem) { 937 HandleScope scope(thread_); 938 ASSERT_FALSE(runFromCStr(runtime_, R"( 939class C: 940 def __class_getitem__(cls, item): 941 return f"C:{cls.__name__}[{item.__name__}]" 942)") 943 .isError()); 944 Type type_c(&scope, mainModuleAt(runtime_, "C")); 945 Type key(&scope, runtime_->typeAt(LayoutId::kInt)); 946 Object result(&scope, objectGetItem(thread_, type_c, key)); 947 EXPECT_TRUE(isStrEqualsCStr(*result, "C:C[int]")); 948} 949 950TEST_F(ObjectBuiltinsTest, ObjectSetAttrSetsInstanceValue) { 951 HandleScope scope(thread_); 952 ASSERT_FALSE(runFromCStr(runtime_, R"( 953class C: pass 954i = C() 955)") 956 .isError()); 957 Object i(&scope, mainModuleAt(runtime_, "i")); 958 Object name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 959 Object value(&scope, runtime_->newInt(47)); 960 EXPECT_TRUE(objectSetAttr(thread_, i, name, value).isNoneType()); 961 EXPECT_TRUE(isIntEqualsWord(objectGetAttribute(thread_, i, name), 47)); 962} 963 964TEST_F(ObjectBuiltinsTest, ObjectSetAttrOnDataDescriptorCallsDunderSet) { 965 HandleScope scope(thread_); 966 ASSERT_FALSE(runFromCStr(runtime_, R"( 967class D: 968 def __set__(self, instance, value): 969 global set_args 970 set_args = (self, instance, value) 971 return "ignored result" 972 def __get__(self, instance, owner): pass 973foo_descr = D() 974class C: 975 foo = foo_descr 976i = C() 977)") 978 .isError()); 979 Object i(&scope, mainModuleAt(runtime_, "i")); 980 Object foo_descr(&scope, mainModuleAt(runtime_, "foo_descr")); 981 Object name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 982 Object value(&scope, runtime_->newInt(47)); 983 EXPECT_TRUE(objectSetAttr(thread_, i, name, value).isNoneType()); 984 Object set_args_obj(&scope, mainModuleAt(runtime_, "set_args")); 985 ASSERT_TRUE(set_args_obj.isTuple()); 986 Tuple dunder_set_args(&scope, *set_args_obj); 987 ASSERT_EQ(dunder_set_args.length(), 3); 988 EXPECT_EQ(dunder_set_args.at(0), foo_descr); 989 EXPECT_EQ(dunder_set_args.at(1), i); 990 EXPECT_TRUE(isIntEqualsWord(dunder_set_args.at(2), 47)); 991} 992 993TEST_F(ObjectBuiltinsTest, ObjectSetAttrPropagatesErrorsInDunderSet) { 994 HandleScope scope(thread_); 995 ASSERT_FALSE(runFromCStr(runtime_, R"( 996class D: 997 def __set__(self, instance, value): raise UserWarning() 998 def __get__(self, instance, owner): pass 999class C: 1000 foo = D() 1001i = C() 1002)") 1003 .isError()); 1004 Object i(&scope, mainModuleAt(runtime_, "i")); 1005 Object name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 1006 Object value(&scope, runtime_->newInt(1)); 1007 EXPECT_TRUE( 1008 raised(objectSetAttr(thread_, i, name, value), LayoutId::kUserWarning)); 1009} 1010 1011TEST_F(ObjectBuiltinsTest, ObjectSetAttrOnNonHeapObjectRaisesAttributeError) { 1012 HandleScope scope(thread_); 1013 Object object(&scope, runtime_->newInt(42)); 1014 Object name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 1015 Object value(&scope, runtime_->newInt(1)); 1016 EXPECT_TRUE(raisedWithStr(objectSetAttr(thread_, object, name, value), 1017 LayoutId::kAttributeError, 1018 "'int' object has no attribute 'foo'")); 1019} 1020 1021TEST_F(ObjectBuiltinsTest, ObjectSetAttrSetLocationSetsValueCachesOffset) { 1022 HandleScope scope(thread_); 1023 ASSERT_FALSE(runFromCStr(runtime_, R"( 1024class C: 1025 def __init__(self): 1026 self.foo = 0 1027i = C() 1028)") 1029 .isError()); 1030 Object i(&scope, mainModuleAt(runtime_, "i")); 1031 Object name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 1032 1033 AttributeInfo info; 1034 Layout layout(&scope, runtime_->layoutOf(*i)); 1035 ASSERT_TRUE(Runtime::layoutFindAttribute(*layout, name, &info)); 1036 ASSERT_TRUE(info.isInObject()); 1037 1038 Object value(&scope, runtime_->newInt(7)); 1039 Object value2(&scope, runtime_->newInt(99)); 1040 Object to_cache(&scope, NoneType::object()); 1041 EXPECT_TRUE(objectSetAttrSetLocation(thread_, i, name, value, &to_cache) 1042 .isNoneType()); 1043 EXPECT_TRUE(isIntEqualsWord(*to_cache, info.offset())); 1044 ASSERT_TRUE(i.isInstance()); 1045 Instance instance(&scope, *i); 1046 EXPECT_TRUE(isIntEqualsWord(instance.instanceVariableAt(info.offset()), 7)); 1047 1048 Interpreter::storeAttrWithLocation(thread_, *i, *to_cache, *value2); 1049 EXPECT_TRUE(isIntEqualsWord(instance.instanceVariableAt(info.offset()), 99)); 1050} 1051 1052TEST_F(ObjectBuiltinsTest, 1053 ObjectSetAttrSetLocationSetsOverflowValueCachesOffset) { 1054 HandleScope scope(thread_); 1055 ASSERT_FALSE(runFromCStr(runtime_, R"( 1056class C: pass 1057i = C() 1058i.foo = 0 1059)") 1060 .isError()); 1061 Object i(&scope, mainModuleAt(runtime_, "i")); 1062 Object name(&scope, Runtime::internStrFromCStr(thread_, "foo")); 1063 1064 AttributeInfo info; 1065 Layout layout(&scope, runtime_->layoutOf(*i)); 1066 ASSERT_TRUE(Runtime::layoutFindAttribute(*layout, name, &info)); 1067 ASSERT_TRUE(info.isOverflow()); 1068 1069 Object value(&scope, runtime_->newInt(-8)); 1070 Object value2(&scope, runtime_->newInt(11)); 1071 Object to_cache(&scope, NoneType::object()); 1072 EXPECT_TRUE(objectSetAttrSetLocation(thread_, i, name, value, &to_cache) 1073 .isNoneType()); 1074 EXPECT_TRUE(isIntEqualsWord(*to_cache, -info.offset() - 1)); 1075 ASSERT_TRUE(i.isHeapObject()); 1076 Instance instance(&scope, *i); 1077 EXPECT_TRUE( 1078 isIntEqualsWord(instanceGetAttribute(thread_, instance, name), -8)); 1079 1080 Interpreter::storeAttrWithLocation(thread_, *i, *to_cache, *value2); 1081 EXPECT_TRUE( 1082 isIntEqualsWord(instanceGetAttribute(thread_, instance, name), 11)); 1083} 1084 1085} // namespace testing 1086} // namespace py