Skip to content

Commit 44cf245

Browse files
committed
Establish BackendFromEnv machinery
1 parent 50785d3 commit 44cf245

3 files changed

Lines changed: 114 additions & 0 deletions

File tree

‎bind/backend.go‎

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
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 bind
6+
7+
import (
8+
"fmt"
9+
"os"
10+
"strings"
11+
)
12+
13+
// BackendEnvVar is the environment variable that selects which tool is used
14+
// to bind the generated cgo shim to CPython.
15+
const BackendEnvVar = "GOPY_BACKEND"
16+
17+
// Backend names a CPython binding tool.
18+
type Backend string
19+
20+
const (
21+
BackendPyBindGen Backend = "pybindgen" // default
22+
BackendCFFI Backend = "cffi"
23+
BackendPyBind11 Backend = "pybind11"
24+
BackendNanobind Backend = "nanobind"
25+
BackendCAPI Backend = "capi"
26+
BackendCGO Backend = "cgo"
27+
)
28+
29+
// backends lists every known backend and whether gopy can generate it yet.
30+
var backends = []struct {
31+
name Backend
32+
implemented bool
33+
}{
34+
{BackendPyBindGen, true},
35+
{BackendCFFI, false},
36+
{BackendPyBind11, false},
37+
{BackendNanobind, false},
38+
{BackendCAPI, false},
39+
{BackendCGO, false},
40+
}
41+
42+
// BackendFromEnv returns the backend selected by GOPY_BACKEND.
43+
// An unset or empty variable selects pybindgen.
44+
func BackendFromEnv() (Backend, error) {
45+
return parseBackend(os.Getenv(BackendEnvVar))
46+
}
47+
48+
func parseBackend(v string) (Backend, error) {
49+
v = strings.ToLower(strings.TrimSpace(v))
50+
if v == "" {
51+
return BackendPyBindGen, nil
52+
}
53+
names := make([]string, len(backends))
54+
for i, b := range backends {
55+
names[i] = string(b.name)
56+
if string(b.name) != v {
57+
continue
58+
}
59+
if !b.implemented {
60+
return "", fmt.Errorf("gopy: %s=%q is not implemented yet", BackendEnvVar, v)
61+
}
62+
return b.name, nil
63+
}
64+
return "", fmt.Errorf("gopy: unknown %s=%q (valid values: %s)", BackendEnvVar, v, strings.Join(names, ", "))
65+
}

‎bind/backend_test.go‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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 bind
6+
7+
import (
8+
"strings"
9+
"testing"
10+
)
11+
12+
func TestParseBackend(t *testing.T) {
13+
for _, tc := range []struct {
14+
in string
15+
want Backend
16+
errPart string
17+
}{
18+
{in: "", want: BackendPyBindGen},
19+
{in: "pybindgen", want: BackendPyBindGen},
20+
{in: " PyBindGen ", want: BackendPyBindGen},
21+
{in: "cffi", errPart: "not implemented yet"},
22+
{in: "bogus", errPart: "unknown GOPY_BACKEND"},
23+
} {
24+
got, err := parseBackend(tc.in)
25+
if tc.errPart != "" {
26+
if err == nil || !strings.Contains(err.Error(), tc.errPart) {
27+
t.Errorf("parseBackend(%q): got err=%v, want error containing %q", tc.in, err, tc.errPart)
28+
}
29+
continue
30+
}
31+
if err != nil || got != tc.want {
32+
t.Errorf("parseBackend(%q) = %q, %v; want %q", tc.in, got, err, tc.want)
33+
}
34+
}
35+
}
36+
37+
func TestBackendFromEnv(t *testing.T) {
38+
t.Setenv(BackendEnvVar, "")
39+
if got, err := BackendFromEnv(); err != nil || got != BackendPyBindGen {
40+
t.Errorf("unset: got %q, %v", got, err)
41+
}
42+
t.Setenv(BackendEnvVar, "bogus")
43+
if _, err := BackendFromEnv(); err == nil {
44+
t.Error("bogus value: want error")
45+
}
46+
}

‎gen.go‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ func genOutDir(odir string) (string, error) {
6363
// mode = gen, build, pkg, exe
6464
func genPkg(mode bind.BuildMode, cfg *BuildCfg) error {
6565
var err error
66+
if _, err = bind.BackendFromEnv(); err != nil {
67+
return err
68+
}
6669
cfg.OutputDir, err = genOutDir(cfg.OutputDir)
6770
if err != nil {
6871
return err

0 commit comments

Comments
 (0)