Skip to content

Commit d059504

Browse files
committed
vm: implement IMPORT_NAME, IMPORT_FROM, IMPORT_STAR; py: factor Attribute code
* Re-arrange and factor Attribute handling * Fix bug in import from curent directory * Implement IMPORT_*
1 parent a20d443 commit d059504

File tree

10 files changed

+147
-37
lines changed

10 files changed

+147
-37
lines changed

builtin/builtin.go

+2-13
Original file line numberDiff line numberDiff line change
@@ -411,12 +411,7 @@ func builtin_getattr(self py.Object, args py.Tuple) py.Object {
411411

412412
py.UnpackTuple(args, nil, "getattr", 2, 3, &v, &name, &dflt)
413413

414-
nameStr, ok := name.(py.String)
415-
if !ok {
416-
panic(py.ExceptionNewf(py.TypeError, "getattr(): attribute name must be string"))
417-
}
418-
419-
result, err := py.GetAttrErr(v, string(nameStr))
414+
result, err := py.GetAttrErr(v, name)
420415
if err != nil {
421416
if dflt == nil {
422417
panic(err)
@@ -435,13 +430,7 @@ func builtin_hasattr(self py.Object, args py.Tuple) py.Object {
435430
var v py.Object
436431
var name py.Object
437432
py.UnpackTuple(args, nil, "hasattr", 2, 2, &v, &name)
438-
439-
nameStr, ok := name.(py.String)
440-
if !ok {
441-
panic(py.ExceptionNewf(py.TypeError, "hasattr(): attribute name must be string"))
442-
}
443-
444-
_, err := py.GetAttrErr(v, string(nameStr))
433+
_, err := py.GetAttrErr(v, name)
445434
return py.NewBool(err == nil)
446435
}
447436

py/import.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212

1313
var (
1414
// This will become sys.path one day ;-)
15-
modulePath = []string{"", "/usr/lib/python3.3", "/usr/local/lib/python3.3/dist-packages", "/usr/lib/python3/dist-packages"}
15+
modulePath = []string{"", "/usr/lib/python3.4", "/usr/local/lib/python3.4/dist-packages", "/usr/lib/python3/dist-packages"}
1616
)
1717

1818
// The workings of __import__
@@ -93,7 +93,7 @@ func ImportModuleLevelObject(name string, globals, locals StringDict, fromlist T
9393
if !ok {
9494
panic(ExceptionNewf(SystemError, "Couldn't find __file__ in globals"))
9595
}
96-
mpath = string(mpathObj.(String))
96+
mpath = path.Dir(string(mpathObj.(String)))
9797
}
9898
fullPath := path.Join(mpath, pathParts)
9999
// FIXME Read pyc/pyo too
@@ -277,7 +277,7 @@ func XImportModuleLevelObject(nameObj, given_globals, locals, given_fromlist Obj
277277
// NOTE: because of this, __initializing__ must be set *before*
278278
// stuffing the new module in sys.modules.
279279

280-
value, err = GetAttrErr(mod, "__initializing__")
280+
value, err = GetAttrStringErr(mod, "__initializing__")
281281
if err == nil {
282282
initializing = bool(MakeBool(value).(Bool))
283283
}

py/internal.go

+22-16
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@
44

55
package py
66

7+
// AttributeName converts an Object to a string, raising a TypeError
8+
// if it wasn't a String
9+
func AttributeName(keyObj Object) string {
10+
if key, ok := keyObj.(String); ok {
11+
return string(key)
12+
}
13+
panic(ExceptionNewf(TypeError, "attribute name must be string, not '%s'", keyObj.Type().Name))
14+
}
15+
716
// Bool is called to implement truth value testing and the built-in
817
// operation bool(); should return False or True. When this method is
918
// not defined, __len__() is called, if it is defined, and the object
@@ -142,10 +151,10 @@ func DelItem(self Object, key Object) Object {
142151
panic(ExceptionNewf(TypeError, "'%s' object does not support item deletion", self.Type().Name))
143152
}
144153

145-
// GetAttrErr - returns the result or an err to be raised if not found
154+
// GetAttrStringErr - returns the result or an err to be raised if not found
146155
//
147156
// Only AttributeErrors will be returned in err, everything else will be raised
148-
func GetAttrErr(self Object, key string) (res Object, err error) {
157+
func GetAttrStringErr(self Object, key string) (res Object, err error) {
149158
defer func() {
150159
if r := recover(); r != nil {
151160
if IsException(AttributeError, r) {
@@ -201,9 +210,16 @@ func GetAttrErr(self Object, key string) (res Object, err error) {
201210
return
202211
}
203212

213+
// GetAttrErr - returns the result or an err to be raised if not found
214+
//
215+
// Only AttributeErrors will be returned in err, everything else will be raised
216+
func GetAttrErr(self Object, keyObj Object) (res Object, err error) {
217+
return GetAttrStringErr(self, AttributeName(keyObj))
218+
}
219+
204220
// GetAttrString gets the attribute, raising an error if not found
205221
func GetAttrString(self Object, key string) Object {
206-
res, err := GetAttrErr(self, key)
222+
res, err := GetAttrStringErr(self, key)
207223
if err != nil {
208224
panic(err)
209225
}
@@ -213,10 +229,7 @@ func GetAttrString(self Object, key string) Object {
213229
// GetAttr gets the attribute rasing an error if key isn't a string or
214230
// attribute not found
215231
func GetAttr(self Object, keyObj Object) Object {
216-
if key, ok := keyObj.(String); ok {
217-
return GetAttrString(self, string(key))
218-
}
219-
panic(ExceptionNewf(TypeError, "attribute name must be string, not '%s'", self.Type().Name))
232+
return GetAttrString(self, AttributeName(keyObj))
220233
}
221234

222235
// SetAttrString
@@ -255,10 +268,7 @@ func SetAttrString(self Object, key string, value Object) Object {
255268

256269
// SetAttr
257270
func SetAttr(self Object, keyObj Object, value Object) Object {
258-
if key, ok := keyObj.(String); ok {
259-
return GetAttrString(self, string(key))
260-
}
261-
panic(ExceptionNewf(TypeError, "attribute name must be string, not '%s'", self.Type().Name))
271+
return GetAttrString(self, AttributeName(keyObj))
262272
}
263273

264274
// DeleteAttrString
@@ -301,9 +311,5 @@ func DeleteAttrString(self Object, key string) {
301311

302312
// DeleteAttr
303313
func DeleteAttr(self Object, keyObj Object) {
304-
if key, ok := keyObj.(String); ok {
305-
DeleteAttrString(self, string(key))
306-
return
307-
}
308-
panic(ExceptionNewf(TypeError, "attribute name must be string, not '%s'", self.Type().Name))
314+
DeleteAttrString(self, AttributeName(keyObj))
309315
}

vm/eval.go

+18-2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ objects so they can be GCed
3535

3636
import (
3737
"runtime/debug"
38+
"strings"
3839

3940
"github.com/ncw/gpython/py"
4041
)
@@ -673,7 +674,22 @@ func do_YIELD_VALUE(vm *Vm, arg int32) {
673674
// names. This opcode implements from module import *.
674675
func do_IMPORT_STAR(vm *Vm, arg int32) {
675676
defer vm.CheckException()
676-
vm.NotImplemented("IMPORT_STAR", arg)
677+
from := vm.POP()
678+
module := from.(*py.Module)
679+
if all, ok := module.Globals["__all__"]; ok {
680+
py.Iterate(all, func(item py.Object) bool {
681+
name := py.AttributeName(item)
682+
vm.frame.Locals[name] = py.GetAttrString(module, name)
683+
return false
684+
})
685+
} else {
686+
for name, value := range module.Globals {
687+
if !strings.HasPrefix(name, "_") {
688+
vm.frame.Locals[name] = value
689+
}
690+
}
691+
}
692+
// FIXME implement STORE_FAST stuff
677693
}
678694

679695
// Removes one block from the block stack. Per frame, there is a stack
@@ -1010,7 +1026,7 @@ func do_IMPORT_FROM(vm *Vm, namei int32) {
10101026
defer vm.CheckException()
10111027
name := vm.frame.Code.Names[namei]
10121028
module := vm.TOP()
1013-
res, err := py.GetAttrErr(module, name)
1029+
res, err := py.GetAttrStringErr(module, name)
10141030
if err != nil {
10151031
// Catch AttributeError and rethrow as ImportError
10161032
if py.IsException(py.AttributeError, err) {

vm/tests/import_from.py

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/usr/bin/env python3.4
2+
3+
# test IMPORT_FROM
4+
5+
from lib import libfn, libvar, libclass
6+
7+
assert libfn() == 42
8+
assert libvar == 43
9+
assert libclass().method() == 44
10+
11+
# End with this
12+
finished = True

vm/tests/import_name.py

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/usr/bin/env python3.4
2+
3+
# test IMPORT_NAME
4+
5+
import lib
6+
7+
assert lib.libfn() == 42
8+
assert lib.libvar == 43
9+
assert lib.libclass().method() == 44
10+
11+
# End with this
12+
finished = True

vm/tests/import_star.py

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env python3.4
2+
3+
# test IMPORT_STAR
4+
5+
from lib import *
6+
7+
assert libfn() == 42
8+
assert libvar == 43
9+
assert libclass().method() == 44
10+
11+
# FIXME - exception catching not working
12+
# ok = False
13+
# try:
14+
# _libprivate
15+
# except NameError:
16+
# ok = True
17+
# assert ok
18+
19+
from lib1 import *
20+
21+
assert lib1fn() == 42
22+
assert lib1var == 43
23+
24+
# FIXME - exception handling broken
25+
# ok = False
26+
# try:
27+
# lib1class
28+
# except NameError:
29+
# ok = True
30+
# assert ok
31+
32+
# FIXME - exception handling broken
33+
# ok = False
34+
# try:
35+
# _libprivate
36+
# except NameError:
37+
# ok = True
38+
# assert ok
39+
40+
# End with this
41+
finished = True

vm/tests/lib.py

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/usr/bin/env python3.4
2+
3+
# Some targets to be imported
4+
5+
def libfn():
6+
return 42
7+
8+
libvar = 43
9+
10+
class libclass:
11+
def method(self):
12+
return 44
13+
14+
_libprivate = 45

vm/tests/lib1.py

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/usr/bin/env python3.4
2+
3+
# Some targets to be imported
4+
5+
__all__ = [
6+
"lib1fn",
7+
"lib1var",
8+
]
9+
10+
def lib1fn():
11+
return 42
12+
13+
lib1var = 43
14+
15+
class lib1class:
16+
def method(self):
17+
return 44
18+
19+
_lib1private = 45

vm/vm_test.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,10 @@ func TestVm(t *testing.T) {
5555
t.Fatalf("ReadDir failed: %v", err)
5656
}
5757
for _, f := range files {
58-
name := path.Join(testDir, f.Name())
59-
if strings.HasSuffix(name, ".py") {
60-
t.Logf("%s: Starting", name)
58+
name := f.Name()
59+
if !strings.HasPrefix(name, "lib") && strings.HasSuffix(name, ".py") {
60+
name := path.Join(testDir, name)
61+
t.Logf("%s: Running", name)
6162
run(t, name)
6263
}
6364
}

0 commit comments

Comments
 (0)