diff --git a/py/run.go b/py/run.go index cd584fc2..b81e09d4 100644 --- a/py/run.go +++ b/py/run.go @@ -143,7 +143,7 @@ func RunSrc(ctx Context, pySrc string, pySrcDesc string, inModule interface{}) ( // // If inModule is a *Module, then the code is run in that module. // -// If inModule is nil, the code is run in a new __main__ module (and the new Module is returned). +// If inModule is nil or a nil *Module, the code is run in a new __main__ module (and the new Module is returned). // // If inModule is a string, the code is run in a new module with the given name (and the new Module is returned). 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 case nil: createNew = true case *Module: + if mod == nil { + createNew = true + break + } _, err = ctx.RunCode(code, mod.Globals, mod.Globals, nil) module = mod default: diff --git a/py/run_test.go b/py/run_test.go new file mode 100644 index 00000000..59b60218 --- /dev/null +++ b/py/run_test.go @@ -0,0 +1,54 @@ +// Copyright 2026 The go-python Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package py_test + +import ( + "os" + "path/filepath" + "testing" + + "github.com/go-python/gpython/py" + _ "github.com/go-python/gpython/stdlib" +) + +func TestRunWithNilModulePointer(t *testing.T) { + for _, entry := range []string{"RunCode", "RunSrc", "RunFile"} { + t.Run(entry, func(t *testing.T) { + ctx := py.NewContext(py.DefaultContextOpts()) + defer ctx.Close() + src := "value = 42\n" + var module *py.Module + var err error + switch entry { + case "RunCode": + var code *py.Code + code, err = py.Compile(src, "", py.ExecMode, 0, true) + if err == nil { + module, err = py.RunCode(ctx, code, "", module) + } + case "RunSrc": + module, err = py.RunSrc(ctx, src, "", module) + case "RunFile": + path := filepath.Join(t.TempDir(), "test.py") + if err = os.WriteFile(path, []byte(src), 0600); err == nil { + module, err = py.RunFile(ctx, filepath.Base(path), py.CompileOpts{CurDir: filepath.Dir(path)}, module) + } + } + if err != nil { + t.Fatal(err) + } + if module == nil || module.Globals["value"] != py.Int(42) { + t.Fatalf("expected a new module containing value = 42, got %v", module) + } + reused, err := py.RunSrc(ctx, "value += 1", "", module) + if err != nil { + t.Fatal(err) + } + if reused != module || module.Globals["value"] != py.Int(43) { + t.Fatal("expected the existing module and globals to be reused") + } + }) + } +}