Skip to content

Commit 2f79b9f

Browse files
committed
Merge remote-tracking branch 'upstream/master'
2 parents 166d489 + b05c0bd commit 2f79b9f

File tree

10 files changed

+355
-8
lines changed

10 files changed

+355
-8
lines changed

builtin/builtin.go

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func init() {
2929
// py.MustNewMethod("callable", builtin_callable, 0, callable_doc),
3030
py.MustNewMethod("chr", builtin_chr, 0, chr_doc),
3131
py.MustNewMethod("compile", builtin_compile, 0, compile_doc),
32-
// py.MustNewMethod("delattr", builtin_delattr, 0, delattr_doc),
32+
py.MustNewMethod("delattr", builtin_delattr, 0, delattr_doc),
3333
// py.MustNewMethod("dir", builtin_dir, 0, dir_doc),
3434
py.MustNewMethod("divmod", builtin_divmod, 0, divmod_doc),
3535
py.MustNewMethod("eval", py.InternalMethodEval, 0, eval_doc),
@@ -44,7 +44,7 @@ func init() {
4444
// py.MustNewMethod("input", builtin_input, 0, input_doc),
4545
// py.MustNewMethod("isinstance", builtin_isinstance, 0, isinstance_doc),
4646
// py.MustNewMethod("issubclass", builtin_issubclass, 0, issubclass_doc),
47-
// py.MustNewMethod("iter", builtin_iter, 0, iter_doc),
47+
py.MustNewMethod("iter", builtin_iter, 0, iter_doc),
4848
py.MustNewMethod("len", builtin_len, 0, len_doc),
4949
py.MustNewMethod("locals", py.InternalMethodLocals, 0, locals_doc),
5050
py.MustNewMethod("max", builtin_max, 0, max_doc),
@@ -633,6 +633,27 @@ func source_as_string(cmd py.Object, funcname, what string /*, PyCompilerFlags *
633633
// return nil;
634634
}
635635

636+
const delattr_doc = `Deletes the named attribute from the given object.
637+
638+
delattr(x, 'y') is equivalent to "del x.y"
639+
`
640+
641+
func builtin_delattr(self py.Object, args py.Tuple) (py.Object, error) {
642+
var v py.Object
643+
var name py.Object
644+
645+
err := py.UnpackTuple(args, nil, "delattr", 2, 2, &v, &name)
646+
if err != nil {
647+
return nil, err
648+
}
649+
650+
err = py.DeleteAttr(v, name)
651+
if err != nil {
652+
return nil, err
653+
}
654+
return py.None, nil
655+
}
656+
636657
const compile_doc = `compile(source, filename, mode[, flags[, dont_inherit]]) -> code object
637658
638659
Compile the source string (a Python module, statement or expression)
@@ -762,6 +783,39 @@ object.
762783
The globals and locals are dictionaries, defaulting to the current
763784
globals and locals. If only globals is given, locals defaults to it.`
764785

786+
const iter_doc = `iter(iterable) -> iterator
787+
iter(callable, sentinel) -> iterator
788+
789+
Get an iterator from an object. In the first form, the argument must
790+
supply its own iterator, or be a sequence.
791+
In the second form, the callable is called until it returns the sentinel.
792+
`
793+
794+
func builtin_iter(self py.Object, args py.Tuple) (py.Object, error) {
795+
nArgs := len(args)
796+
if nArgs < 1 {
797+
return nil, py.ExceptionNewf(py.TypeError,
798+
"iter expected at least 1 arguments, got %d",
799+
nArgs)
800+
} else if nArgs > 2 {
801+
return nil, py.ExceptionNewf(py.TypeError,
802+
"iter expected at most 2 arguments, got %d",
803+
nArgs)
804+
}
805+
806+
v := args[0]
807+
if nArgs == 1 {
808+
return py.Iter(v)
809+
}
810+
_, ok := v.(*py.Function)
811+
sentinel := args[1]
812+
if !ok {
813+
return nil, py.ExceptionNewf(py.TypeError,
814+
"iter(v, w): v must be callable")
815+
}
816+
return py.NewCallIterator(v, sentinel), nil
817+
}
818+
765819
// For code see vm/builtin.go
766820

767821
const len_doc = `len(object) -> integer

builtin/tests/builtin.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,50 @@ def func(p):
132132
ok = True
133133
assert ok, "ValueError not raised"
134134

135+
doc="iter"
136+
cnt = 0
137+
def f():
138+
global cnt
139+
cnt += 1
140+
return cnt
141+
142+
l = list(iter(f,20))
143+
assert len(l) == 19
144+
for idx, v in enumerate(l):
145+
assert idx + 1 == v
146+
147+
words1 = ['g', 'p', 'y', 't', 'h', 'o', 'n']
148+
words2 = list(iter(words1))
149+
for w1, w2 in zip(words1, words2):
150+
assert w1 == w2
151+
152+
ok = False
153+
try:
154+
iter()
155+
except TypeError:
156+
ok = True
157+
finally:
158+
assert ok, "TypeError not raised"
159+
ok = False
160+
161+
try:
162+
l = [1, 2, 3]
163+
iter(l, 2)
164+
except TypeError:
165+
ok = True
166+
finally:
167+
assert ok, "TypeError not raised"
168+
ok = False
169+
170+
try:
171+
iter(f, 2, 3)
172+
except TypeError:
173+
ok = True
174+
finally:
175+
assert ok, "TypeError not raised"
176+
ok = False
177+
178+
135179
doc="next no default"
136180
def gen():
137181
yield 1
@@ -256,6 +300,15 @@ class C: pass
256300
setattr(c, "potato", "spud")
257301
assert getattr(c, "potato") == "spud"
258302
assert c.potato == "spud"
303+
delattr(c, "potato")
304+
assert not hasattr(c, "potato")
305+
ok = False
306+
try:
307+
delattr(c, "potato")
308+
except AttributeError as e:
309+
ok = True
310+
finally:
311+
assert ok
259312

260313
doc="sum"
261314
assert sum([1,2,3]) == 6

py/call_iterator.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright 2019 The go-python Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// CallIterator objects
6+
7+
package py
8+
9+
// A python CallIterator object
10+
type CallIterator struct {
11+
callable Object
12+
sentinel Object
13+
}
14+
15+
var CallIteratorType = NewType("callable_iterator", "callable_iterator type")
16+
17+
// Type of this object
18+
func (o *CallIterator) Type() *Type {
19+
return CallIteratorType
20+
}
21+
22+
func (cit *CallIterator) M__iter__() (Object, error) {
23+
return cit, nil
24+
}
25+
26+
// Get next one from the iteration
27+
func (cit *CallIterator) M__next__() (Object, error) {
28+
value, err := Call(cit.callable, nil, nil)
29+
30+
if err != nil {
31+
return nil, err
32+
}
33+
34+
if value == cit.sentinel {
35+
return nil, StopIteration
36+
}
37+
38+
return value, nil
39+
}
40+
41+
// Define a new CallIterator
42+
func NewCallIterator(callable Object, sentinel Object) *CallIterator {
43+
c := &CallIterator{
44+
callable: callable,
45+
sentinel: sentinel,
46+
}
47+
return c
48+
}
49+
50+
// Check interface is satisfied
51+
var _ I_iterator = (*CallIterator)(nil)

py/classmethod.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ func (c *ClassMethod) GetDict() StringDict {
4444

4545
// ClassMethodNew
4646
func ClassMethodNew(metatype *Type, args Tuple, kwargs StringDict) (res Object, err error) {
47-
c := &ClassMethod{}
47+
c := &ClassMethod{
48+
Dict: make(StringDict),
49+
}
4850
err = UnpackTuple(args, kwargs, "classmethod", 1, 1, &c.Callable)
4951
if err != nil {
5052
return nil, err

py/function.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ func NewFunction(code *Code, globals StringDict, qualname string) *Function {
8484
Name: code.Name,
8585
Doc: doc,
8686
Module: module,
87+
Dict: make(StringDict),
8788
}
8889
}
8990

@@ -193,10 +194,6 @@ func init() {
193194
f.Dict = dict
194195
return nil
195196
},
196-
Fdel: func(self Object) error {
197-
self.(*Function).Dict = nil
198-
return nil
199-
},
200197
}
201198
FunctionType.Dict["__name__"] = &Property{
202199
Fget: func(self Object) (Object, error) {

py/staticmethod.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ func (c *StaticMethod) GetDict() StringDict {
4141

4242
// StaticMethodNew
4343
func StaticMethodNew(metatype *Type, args Tuple, kwargs StringDict) (res Object, err error) {
44-
c := &StaticMethod{}
44+
c := &StaticMethod{
45+
Dict: make(StringDict),
46+
}
4547
err = UnpackTuple(args, kwargs, "staticmethod", 1, 1, &c.Callable)
4648
if err != nil {
4749
return nil, err

py/tests/classmethod.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Copyright 2019 The go-python Authors. All rights reserved.
2+
# Use of this source code is governed by a BSD-style
3+
# license that can be found in the LICENSE file.
4+
5+
doc="classmethod"
6+
7+
class A:
8+
@classmethod
9+
def fn(cls, p):
10+
assert cls is A
11+
return p+1
12+
13+
a = A()
14+
assert a.fn(1) == 2
15+
16+
a.x = 3
17+
assert a.x == 3
18+
19+
doc="finished"

py/tests/function.py

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# Copyright 2019 The go-python Authors. All rights reserved.
2+
# Use of this source code is governed by a BSD-style
3+
# license that can be found in the LICENSE file.
4+
5+
doc="function"
6+
7+
def fn(p):
8+
"docstring"
9+
return p+1
10+
11+
assert fn(1) == 2
12+
13+
# FIXME this doesn't work yet
14+
#assert fn.__doc__ == "docstring"
15+
#fn.__doc__ = "hello"
16+
#assert fn.__doc__ == "hello"
17+
18+
assert str(type(fn)) == "<class 'function'>"
19+
20+
fn.x = 3
21+
assert fn.x == 3
22+
23+
def f2(p):
24+
return p+2
25+
26+
doc="check __code__"
27+
fn.__code__ = f2.__code__
28+
assert fn(1) == 3
29+
try:
30+
fn.__code__ = "bad"
31+
except TypeError:
32+
pass
33+
else:
34+
assert False, "TypeError not raised"
35+
36+
doc="check __defaults__"
37+
def f3(p=2):
38+
return p
39+
assert f3.__defaults__ == (2,)
40+
assert f3() == 2
41+
f3.__defaults__ = (10,)
42+
assert f3() == 10
43+
assert f3.__defaults__ == (10,)
44+
try:
45+
f3.__defaults__ = "bad"
46+
except TypeError:
47+
pass
48+
else:
49+
assert False, "TypeError not raised"
50+
del f3.__defaults__
51+
assert f3.__defaults__ == None or f3.__defaults__ == ()
52+
53+
doc="check __kwdefaults__"
54+
def f4(*, b=2):
55+
return b
56+
assert f4.__kwdefaults__ == {"b":2}
57+
assert f4() == 2
58+
f4.__kwdefaults__ = {"b":10}
59+
assert f4() == 10
60+
assert f4.__kwdefaults__ == {"b":10}
61+
try:
62+
f4.__kwdefaults__ = "bad"
63+
except TypeError:
64+
pass
65+
else:
66+
assert False, "TypeError not raised"
67+
del f4.__kwdefaults__
68+
assert f4.__kwdefaults__ == None or f4.__kwdefaults__ == {}
69+
70+
doc="check __annotations__"
71+
def f5(a: "potato") -> "sausage":
72+
pass
73+
assert f5.__annotations__ == {'a': 'potato', 'return': 'sausage'}
74+
f5.__annotations__ = {'a': 'potato', 'return': 'SAUSAGE'}
75+
assert f5.__annotations__ == {'a': 'potato', 'return': 'SAUSAGE'}
76+
try:
77+
f5.__annotations__ = "bad"
78+
except TypeError:
79+
pass
80+
else:
81+
assert False, "TypeError not raised"
82+
del f5.__annotations__
83+
assert f5.__annotations__ == None or f5.__annotations__ == {}
84+
85+
doc="check __dict__"
86+
def f6():
87+
pass
88+
assert f6.__dict__ == {}
89+
f6.__dict__ = {'a': 'potato'}
90+
assert f6.__dict__ == {'a': 'potato'}
91+
try:
92+
f6.__dict__ = "bad"
93+
except TypeError:
94+
pass
95+
else:
96+
assert False, "TypeError not raised"
97+
try:
98+
del f6.__dict__
99+
except (TypeError, AttributeError):
100+
pass
101+
else:
102+
assert False, "Error not raised"
103+
104+
doc="check __name__"
105+
def f7():
106+
pass
107+
assert f7.__name__ == "f7"
108+
f7.__name__ = "new_name"
109+
assert f7.__name__ == "new_name"
110+
try:
111+
f7.__name__ = 1
112+
except TypeError:
113+
pass
114+
else:
115+
assert False, "TypeError not raised"
116+
117+
doc="check __qualname__"
118+
def f8():
119+
pass
120+
assert f8.__qualname__ == "f8"
121+
f8.__qualname__ = "new_qualname"
122+
assert f8.__qualname__ == "new_qualname"
123+
try:
124+
f8.__qualname__ = 1
125+
except TypeError:
126+
pass
127+
else:
128+
assert False, "TypeError not raised"
129+
130+
doc="finished"

0 commit comments

Comments
 (0)