-
Notifications
You must be signed in to change notification settings - Fork 635
Import wildcard #263
base: master
Are you sure you want to change the base?
Import wildcard #263
Changes from 5 commits
7486214
b119172
ccfdcb9
b95d298
cfcd4c3
bf75ff9
b97e1f3
9fa283c
3515086
4deb42a
0724218
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -179,6 +179,67 @@ func ImportNativeModule(f *Frame, name string, members map[string]*Object) (*Obj | |
| return prev, nil | ||
| } | ||
|
|
||
| // LoadMembers scans over all the members in module | ||
| // and populates globals with them, taking __all__ into | ||
| // account. | ||
| func LoadMembers(f *Frame, module *Object) *BaseException { | ||
| allAttr, raised := GetAttr(f, module, NewStr("__all__"), nil) | ||
| if raised != nil && !raised.isInstance(AttributeErrorType) { | ||
| return raised | ||
| } | ||
| f.RestoreExc(nil, nil) | ||
|
|
||
| if raised == nil { | ||
| raised = loadMembersFromIterable(f, module, allAttr, nil) | ||
| if raised != nil { | ||
| return raised | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // Fall back on __dict__ | ||
| dictAttr, raised := GetAttr(f, module, NewStr("__dict__"), nil) | ||
| if raised != nil && !raised.isInstance(AttributeErrorType) { | ||
| return raised | ||
| } | ||
| raised = loadMembersFromIterable(f, module, dictAttr, func(key *Object) bool { | ||
| return strings.HasPrefix(toStrUnsafe(key).value, "_") | ||
| }) | ||
| if raised != nil { | ||
| return raised | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| func loadMembersFromIterable(f *Frame, module, iterable *Object, filterF func(*Object) bool) *BaseException { | ||
| iter, raised := Iter(f, iterable) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you use seqForEach from seq.go here? |
||
| if raised != nil { | ||
| return raised | ||
| } | ||
|
|
||
| memberName, raised := Next(f, iter) | ||
| for ; raised == nil; memberName, raised = Next(f, iter) { | ||
| member, raised := GetAttr(f, module, toStrUnsafe(memberName), nil) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. memberName may not be a string so this unsafe conversion is not .. safe :) It's worth looking at the CPython source to see what happens with non-string members in
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So I read the source code and it seems to raise several errors:
Looking over the exceptions, there are already a few covered ones, without changing the code:
So, what I should focus on is:
WDYT? |
||
| if raised != nil { | ||
| return raised | ||
| } | ||
| if filterF != nil { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| if filterF(memberName) { | ||
| continue | ||
| } | ||
| } | ||
| raised = f.Globals().SetItem(f, memberName, member) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe stash the globals dict in a local variable at the top of the function. |
||
| if raised != nil { | ||
| return raised | ||
| } | ||
| } | ||
| if !raised.isInstance(StopIterationType) { | ||
| return raised | ||
| } | ||
| f.RestoreExc(nil, nil) | ||
| return nil | ||
| } | ||
|
|
||
| // newModule creates a new Module object with the given fully qualified name | ||
| // (e.g a.b.c) and its corresponding Python filename. | ||
| func newModule(name, filename string) *Module { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -204,6 +204,54 @@ func TestImportNativeModule(t *testing.T) { | |
| } | ||
| } | ||
|
|
||
| func TestLoadMembers(t *testing.T) { | ||
| f := NewRootFrame() | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I recommend using the the runInvokeTestCase pattern used in other tests if at all possible. It takes care of a number of things like frame creation and handling exceptions. You could return the globals dictionary that gets populated and check that against your expectation. Something like: |
||
| var1 := NewStr("var1").ToObject() | ||
| var2 := NewStr("_var2").ToObject() | ||
| var3 := NewStr("var3").ToObject() | ||
| nameAttr := NewStr("__name__").ToObject() | ||
| allAttr := NewStr("__all__") | ||
| val1 := NewStr("val1").ToObject() | ||
| val2 := NewStr("val2").ToObject() | ||
| val3 := NewStr("val3").ToObject() | ||
| nameValue := NewStr("foo").ToObject() | ||
| allValue := newTestList(var1, var2).ToObject() | ||
|
|
||
| allDefinedDict := newTestDict(var1, val1, var2, val2, var3, val3, nameAttr, nameValue, allAttr, allValue) | ||
| fooAllDefinedModule := &Module{Object: Object{typ: testModuleType, dict: allDefinedDict}} | ||
| allUndefinedDict := newTestDict(var1, val1, var2, val2, var3, val3, nameAttr, nameValue) | ||
| fooAllUndefinedModule := &Module{Object: Object{typ: testModuleType, dict: allUndefinedDict}} | ||
|
|
||
| cases := []struct { | ||
| module *Module | ||
| wantGlobals *Dict | ||
| }{ | ||
| { | ||
| fooAllDefinedModule, | ||
| newTestDict(var1, val1, var2, val2), | ||
| }, | ||
| { | ||
| fooAllUndefinedModule, | ||
| newTestDict(var1, val1, var3, val3), | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would be good to test some of the corner cases like when |
||
| }, | ||
| } | ||
| for _, cas := range cases { | ||
| f.globals = NewDict() | ||
| raised := LoadMembers(f, cas.module.ToObject()) | ||
| if raised != nil { | ||
| t.Errorf("LoadMmembers: raised %v", raised) | ||
| } | ||
| ne := mustNotRaise(NE(f, f.Globals().ToObject(), cas.wantGlobals.ToObject())) | ||
| b, raised := IsTrue(f, ne) | ||
| if raised != nil { | ||
| panic(raised) | ||
| } | ||
| if b { | ||
| t.Errorf("LoadMembers: Globals() = %v, want %v", f.Globals(), cas.wantGlobals) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| func TestModuleGetNameAndFilename(t *testing.T) { | ||
| fun := wrapFuncForTest(func(f *Frame, m *Module) (*Tuple, *BaseException) { | ||
| name, raised := m.GetName(f) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's simpler to use the dict field of the Object struct:
module.dict