Skip to content

Commit 068ce1b

Browse files
committed
py: handle nil module pointers in RunCode
1 parent 444ae5e commit 068ce1b

2 files changed

Lines changed: 59 additions & 1 deletion

File tree

‎py/run.go‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ func RunSrc(ctx Context, pySrc string, pySrcDesc string, inModule interface{}) (
143143
//
144144
// If inModule is a *Module, then the code is run in that module.
145145
//
146-
// If inModule is nil, the code is run in a new __main__ module (and the new Module is returned).
146+
// If inModule is nil or a nil *Module, the code is run in a new __main__ module (and the new Module is returned).
147147
//
148148
// If inModule is a string, the code is run in a new module with the given name (and the new Module is returned).
149149
func RunCode(ctx Context, code *Code, codeDesc string, inModule interface{}) (*Module, error) {
@@ -162,6 +162,10 @@ func RunCode(ctx Context, code *Code, codeDesc string, inModule interface{}) (*M
162162
case nil:
163163
createNew = true
164164
case *Module:
165+
if mod == nil {
166+
createNew = true
167+
break
168+
}
165169
_, err = ctx.RunCode(code, mod.Globals, mod.Globals, nil)
166170
module = mod
167171
default:

‎py/run_test.go‎

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright 2026 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+
package py_test
6+
7+
import (
8+
"os"
9+
"path/filepath"
10+
"testing"
11+
12+
"github.com/go-python/gpython/py"
13+
_ "github.com/go-python/gpython/stdlib"
14+
)
15+
16+
func TestRunWithNilModulePointer(t *testing.T) {
17+
for _, entry := range []string{"RunCode", "RunSrc", "RunFile"} {
18+
t.Run(entry, func(t *testing.T) {
19+
ctx := py.NewContext(py.DefaultContextOpts())
20+
defer ctx.Close()
21+
src := "value = 42\n"
22+
var module *py.Module
23+
var err error
24+
switch entry {
25+
case "RunCode":
26+
var code *py.Code
27+
code, err = py.Compile(src, "<test>", py.ExecMode, 0, true)
28+
if err == nil {
29+
module, err = py.RunCode(ctx, code, "<test>", module)
30+
}
31+
case "RunSrc":
32+
module, err = py.RunSrc(ctx, src, "<test>", module)
33+
case "RunFile":
34+
path := filepath.Join(t.TempDir(), "test.py")
35+
if err = os.WriteFile(path, []byte(src), 0600); err == nil {
36+
module, err = py.RunFile(ctx, filepath.Base(path), py.CompileOpts{CurDir: filepath.Dir(path)}, module)
37+
}
38+
}
39+
if err != nil {
40+
t.Fatal(err)
41+
}
42+
if module == nil || module.Globals["value"] != py.Int(42) {
43+
t.Fatalf("expected a new module containing value = 42, got %v", module)
44+
}
45+
reused, err := py.RunSrc(ctx, "value += 1", "<reuse>", module)
46+
if err != nil {
47+
t.Fatal(err)
48+
}
49+
if reused != module || module.Globals["value"] != py.Int(43) {
50+
t.Fatal("expected the existing module and globals to be reused")
51+
}
52+
})
53+
}
54+
}

0 commit comments

Comments
 (0)