Commit cd0345d9 authored by YOU's avatar YOU Committed by Dylan Trotter

Add builtin delattr (#202)

parent 947f6ad4
...@@ -303,6 +303,13 @@ func builtinCmp(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { ...@@ -303,6 +303,13 @@ func builtinCmp(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
return Compare(f, args[0], args[1]) return Compare(f, args[0], args[1])
} }
func builtinDelAttr(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
if raised := checkFunctionArgs(f, "delattr", args, ObjectType, StrType); raised != nil {
return nil, raised
}
return None, DelAttr(f, args[0], toStrUnsafe(args[1]))
}
func builtinDir(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { func builtinDir(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
// TODO: Support __dir__. // TODO: Support __dir__.
if raised := checkFunctionArgs(f, "dir", args, ObjectType); raised != nil { if raised := checkFunctionArgs(f, "dir", args, ObjectType); raised != nil {
...@@ -646,6 +653,7 @@ func init() { ...@@ -646,6 +653,7 @@ func init() {
"callable": newBuiltinFunction("callable", builtinCallable).ToObject(), "callable": newBuiltinFunction("callable", builtinCallable).ToObject(),
"chr": newBuiltinFunction("chr", builtinChr).ToObject(), "chr": newBuiltinFunction("chr", builtinChr).ToObject(),
"cmp": newBuiltinFunction("cmp", builtinCmp).ToObject(), "cmp": newBuiltinFunction("cmp", builtinCmp).ToObject(),
"delattr": newBuiltinFunction("delattr", builtinDelAttr).ToObject(),
"dir": newBuiltinFunction("dir", builtinDir).ToObject(), "dir": newBuiltinFunction("dir", builtinDir).ToObject(),
"False": False.ToObject(), "False": False.ToObject(),
"getattr": newBuiltinFunction("getattr", builtinGetAttr).ToObject(), "getattr": newBuiltinFunction("getattr", builtinGetAttr).ToObject(),
......
...@@ -23,6 +23,37 @@ import ( ...@@ -23,6 +23,37 @@ import (
"testing" "testing"
) )
func TestBuiltinDelAttr(t *testing.T) {
f := NewRootFrame()
delattr := mustNotRaise(Builtins.GetItemString(f, "delattr"))
fooType := newTestClass("Foo", []*Type{ObjectType}, NewDict())
fooForDelAttr := newObject(fooType)
mustNotRaise(nil, SetAttr(f, fooForDelAttr, NewStr("bar"), None))
fun := wrapFuncForTest(func(f *Frame, args ...*Object) (*Object, *BaseException) {
result, raised := delattr.Call(f, args, nil)
if raised != nil {
return nil, raised
}
val, raised := GetAttr(f, args[0], toStrUnsafe(args[1]), nil)
if raised != nil && raised.isInstance(AttributeErrorType) {
f.RestoreExc(nil, nil)
return newTestTuple(result, val == nil).ToObject(), nil
}
return nil, f.RaiseType(AttributeErrorType, fmt.Sprintf("'delattr' failed to remove '%s', got '%s' instead", args[1], val))
})
cases := []invokeTestCase{
{args: wrapArgs(fooForDelAttr, "bar"), want: newTestTuple(None, True.ToObject()).ToObject()},
{args: wrapArgs(fooForDelAttr, "baz"), wantExc: mustCreateException(AttributeErrorType, "'Foo' object has no attribute 'baz'")},
{args: wrapArgs(fooForDelAttr), wantExc: mustCreateException(TypeErrorType, "'delattr' requires 2 arguments")},
{args: wrapArgs(fooForDelAttr, "foo", "bar"), wantExc: mustCreateException(TypeErrorType, "'delattr' requires 2 arguments")},
}
for _, cas := range cases {
if err := runInvokeTestCase(fun, &cas); err != "" {
t.Error(err)
}
}
}
func TestBuiltinFuncs(t *testing.T) { func TestBuiltinFuncs(t *testing.T) {
f := NewRootFrame() f := NewRootFrame()
objectDir := ObjectType.dict.Keys(f) objectDir := ObjectType.dict.Keys(f)
...@@ -359,25 +390,27 @@ func TestBuiltinPrint(t *testing.T) { ...@@ -359,25 +390,27 @@ func TestBuiltinPrint(t *testing.T) {
} }
func TestBuiltinSetAttr(t *testing.T) { func TestBuiltinSetAttr(t *testing.T) {
setattr := mustNotRaise(Builtins.GetItemString(NewRootFrame(), "setattr"))
fooType := newTestClass("Foo", []*Type{ObjectType}, newStringDict(map[string]*Object{}))
foo := newObject(fooType)
fun := wrapFuncForTest(func(f *Frame, args ...*Object) (*Object, *BaseException) { fun := wrapFuncForTest(func(f *Frame, args ...*Object) (*Object, *BaseException) {
fooObject := newTestClass("Foo", []*Type{ObjectType}, newStringDict(map[string]*Object{})).ToObject() result, raised := setattr.Call(f, args, nil)
result, raised := builtinSetAttr(f, append(Args{fooObject}, args...), nil)
if raised != nil { if raised != nil {
return nil, raised return nil, raised
} }
val, raised := GetAttr(f, fooObject, toStrUnsafe(args[0]), nil) val, raised := GetAttr(f, args[0], toStrUnsafe(args[1]), nil)
if raised != nil { if raised != nil {
return nil, raised return nil, raised
} }
return newTestTuple(result, val).ToObject(), nil return newTestTuple(result, val).ToObject(), nil
}) })
cases := []invokeTestCase{ cases := []invokeTestCase{
{args: wrapArgs(), wantExc: mustCreateException(TypeErrorType, "'setattr' requires 3 arguments")}, {args: wrapArgs(foo), wantExc: mustCreateException(TypeErrorType, "'setattr' requires 3 arguments")},
{args: wrapArgs("foo", "bar"), want: newTestTuple(None, "bar").ToObject()}, {args: wrapArgs(newObject(fooType), "foo", "bar"), want: newTestTuple(None, "bar").ToObject()},
{args: wrapArgs("foo", 123), want: newTestTuple(None, 123).ToObject()}, {args: wrapArgs(newObject(fooType), "foo", 123), want: newTestTuple(None, 123).ToObject()},
{args: wrapArgs("foo"), wantExc: mustCreateException(TypeErrorType, "'setattr' requires 3 arguments")}, {args: wrapArgs(foo, "foo"), wantExc: mustCreateException(TypeErrorType, "'setattr' requires 3 arguments")},
{args: wrapArgs("foo", 123, None), wantExc: mustCreateException(TypeErrorType, "'setattr' requires 3 arguments")}, {args: wrapArgs(foo, "foo", 123, None), wantExc: mustCreateException(TypeErrorType, "'setattr' requires 3 arguments")},
{args: wrapArgs(123, 123), wantExc: mustCreateException(TypeErrorType, "'setattr' requires a 'str' object but received a \"int\"")}, {args: wrapArgs(foo, 123, 123), wantExc: mustCreateException(TypeErrorType, "'setattr' requires a 'str' object but received a \"int\"")},
} }
for _, cas := range cases { for _, cas := range cases {
if err := runInvokeTestCase(fun, &cas); err != "" { if err := runInvokeTestCase(fun, &cas); err != "" {
......
...@@ -247,7 +247,7 @@ a, b = NoCmp(1), Cmp(2) ...@@ -247,7 +247,7 @@ a, b = NoCmp(1), Cmp(2)
assert cmp(a, b) == -1 assert cmp(a, b) == -1
assert b.cmp_called assert b.cmp_called
# Test setattr # Test delattr
class Foo(object): class Foo(object):
pass pass
...@@ -255,6 +255,32 @@ class Foo(object): ...@@ -255,6 +255,32 @@ class Foo(object):
setattr(Foo, "a", 1) setattr(Foo, "a", 1)
assert Foo.a == 1 # pylint: disable=no-member assert Foo.a == 1 # pylint: disable=no-member
delattr(Foo, "a")
assert getattr(Foo, "a", None) is None
try:
delattr(Foo, 1, "a")
assert AssertionError
except TypeError:
pass
try:
delattr(Foo)
assert AssertionError
except TypeError:
pass
try:
delattr(Foo, "a", 1)
assert AssertionError
except TypeError:
pass
# Test setattr
setattr(Foo, "a", 1)
assert Foo.a == 1 # pylint: disable=no-member
try: try:
setattr(Foo, 1, "a") setattr(Foo, 1, "a")
assert AssertionError assert AssertionError
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment