-
Notifications
You must be signed in to change notification settings - Fork 95
added examples and py utils #159
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
97ee211
added examples and py utils
41984ce
readme tweaks
835e6b0
embedding example now also a test
cdf3d5b
Update examples/embedding/mylib.module.go
drew-512 3dff766
Update examples/embedding/main_test.go
drew-512 249e14e
Update examples/embedding/main_test.go
drew-512 76c8b51
Update examples/embedding/main_test.go
drew-512 17f2690
Update examples/embedding/main_test.go
drew-512 e0f7a11
Update examples/embedding/main_test.go
drew-512 4a49a6d
CI-friendly golden testing fixes
16ebe64
golden test output no longer platform specific
3d37384
Update examples/embedding/main_test.go
drew-512 ba0f3da
Update examples/embedding/main_test.go
drew-512 c67547f
Update examples/embedding/lib/mylib.py
drew-512 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,3 +11,4 @@ cover.out | |
|
||
# tests | ||
builtin/testfile | ||
examples/embedding/embedding |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
## Embedding gpython | ||
|
||
This is an example demonstrating how to embed gpython into a Go application. | ||
|
||
|
||
### Why embed gpython? | ||
|
||
Embedding a highly capable and familiar "interpreted" language allows your users | ||
to easily augment app behavior, configuration, and customization -- all post-deployment. | ||
|
||
Have you ever discovered an exciting software project but lost interest when you had to also | ||
learn its esoteric language schema? In an era of limited attention span, | ||
most people are generally turned off if they have to learn a new language in addition to learning | ||
to use your app. | ||
|
||
If you consider [why use Python](https://www.stxnext.com/what-is-python-used-for/), then perhaps also | ||
consider that your users will be interested to hear that your software offers | ||
even more value that it can be driven from a scripting language they already know. | ||
|
||
Python is widespread in finance, sciences, hobbyist programming and is often | ||
endearingly regarded as most popular programming language for non-developers. | ||
If your application can be driven by embedded Python, then chances are others will | ||
feel excited and empowered that your project can be used out of the box | ||
and feel like familiar territory. | ||
|
||
### But what about the lack of python modules? | ||
|
||
There are only be a small number of native modules available, but don't forget you have the entire | ||
Go standard library and *any* Go package you can name at your fingertips to expose! | ||
This plus multi-context capability gives gpython enormous potential on how it can | ||
serve you. | ||
|
||
So basically, gpython is only off the table if you need to run python that makes heavy use of | ||
modules that are only available in CPython. | ||
|
||
### Packing List | ||
|
||
| | | | ||
|---------------------- | ------------------------------------------------------------------| | ||
| `main.go` | if no args, runs in REPL mode, otherwise runs the given file | | ||
| `lib/mylib.py` | models a library that your application would expose for users | | ||
| `lib/REPL-startup.py` | invoked by `main.go` when starting REPL mode | | ||
| `mylib-demo.py` | models a user-authored script that consumes `mylib` | | ||
| `mylib.module.go` | Go implementation of `mylib_go` consumed by `mylib` | | ||
|
||
|
||
### Invoking a Python Script | ||
|
||
```bash | ||
$ cd examples/embedding/ | ||
$ go build . | ||
$ ./embedding mylib-demo.py | ||
``` | ||
``` | ||
Welcome to a gpython embedded example, | ||
where your wildest Go-based python dreams come true! | ||
|
||
========================================================== | ||
Python 3.4 (github.com/go-python/gpython) | ||
go1.17.6 on darwin amd64 | ||
========================================================== | ||
|
||
Spring Break itinerary: | ||
Stop 1: Miami, Florida | 7 nights | ||
Stop 2: Mallorca, Spain | 3 nights | ||
Stop 3: Ibiza, Spain | 14 nights | ||
Stop 4: Monaco | 12 nights | ||
### Made with Vacaton 1.0 by Fletch F. Fletcher | ||
|
||
I bet Monaco will be the best! | ||
``` | ||
|
||
### REPL Mode | ||
|
||
```bash | ||
$ ./embedding | ||
``` | ||
``` | ||
======= Entering REPL mode, press Ctrl+D to exit ======= | ||
|
||
========================================================== | ||
Python 3.4 (github.com/go-python/gpython) | ||
go1.17.6 on darwin amd64 | ||
========================================================== | ||
|
||
>>> v = Vacation("Spring Break", Stop("Florida", 3), Stop("Nice", 7)) | ||
>>> print(str(v)) | ||
Spring Break, 2 stop(s) | ||
>>> v.PrintItinerary() | ||
Spring Break itinerary: | ||
Stop 1: Florida | 3 nights | ||
Stop 2: Nice | 7 nights | ||
### Made with Vacaton 1.0 by Fletch F. Fletcher | ||
``` | ||
|
||
## Takeways | ||
|
||
- `main.go` demonstrates high-level convenience functions such as `py.RunFile()`. | ||
- Embedding a Go `struct` as a Python object only requires that it implement `py.Object`, which is a single function: | ||
`Type() *py.Type` | ||
- See [py/run.go](https://github.com/go-python/gpython/tree/master/py/run.go) for more about interpreter instances and `py.Context` | ||
- Helper functions are available in [py/util.go](https://github.com/go-python/gpython/tree/master/py/util.go) and your contributions are welcome! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
|
||
|
||
# This file is called from main.go when in REPL mode | ||
|
||
# This is here to demonstrate making life easier for your users in REPL mode | ||
# by doing pre-setup here so they don't have to import every time they start. | ||
from mylib import * | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import mylib_go as _go | ||
|
||
PY_VERSION = _go.PY_VERSION | ||
|
||
|
||
print(''' | ||
========================================================== | ||
%s | ||
========================================================== | ||
''' % (PY_VERSION, )) | ||
|
||
|
||
def Stop(location, num_nights = 2): | ||
return _go.VacationStop_new(location, num_nights) | ||
|
||
|
||
class Vacation: | ||
|
||
def __init__(self, tripName, *stops): | ||
self._v, self._libVers = _go.Vacation_new() | ||
self.tripName = tripName | ||
self.AddStops(*stops) | ||
|
||
def __str__(self): | ||
return "%s, %d stop(s)" % (self.tripName, self.NumStops()) | ||
|
||
def NumStops(self): | ||
return self._v.num_stops() | ||
|
||
def GetStop(self, stop_num): | ||
return self._v.get_stop(stop_num) | ||
|
||
def AddStops(self, *stops): | ||
self._v.add_stops(stops) | ||
|
||
def PrintItinerary(self): | ||
print(self.tripName, "itinerary:") | ||
i = 1 | ||
while 1: | ||
|
||
try: | ||
stop = self.GetStop(i) | ||
except IndexError: | ||
break | ||
|
||
print(" Stop %d: %s" % (i, str(stop))) | ||
i += 1 | ||
|
||
print("### Made with %s " % self._libVers) | ||
|
||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// Copyright 2022 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 main | ||
|
||
import ( | ||
"flag" | ||
"fmt" | ||
|
||
// This initializes gpython for runtime execution and is essential. | ||
// It defines forward-declared symbols and registers native built-in modules, such as sys and time. | ||
_ "github.com/go-python/gpython/modules" | ||
|
||
// Commonly consumed gpython | ||
"github.com/go-python/gpython/py" | ||
"github.com/go-python/gpython/repl" | ||
"github.com/go-python/gpython/repl/cli" | ||
) | ||
|
||
func main() { | ||
flag.Parse() | ||
runWithFile(flag.Arg(0)) | ||
} | ||
|
||
func runWithFile(pyFile string) error { | ||
|
||
// See type Context interface and related docs | ||
ctx := py.NewContext(py.DefaultContextOpts()) | ||
|
||
var err error | ||
if len(pyFile) == 0 { | ||
replCtx := repl.New(ctx) | ||
|
||
fmt.Print("\n======= Entering REPL mode, press Ctrl+D to exit =======\n") | ||
|
||
_, err = py.RunFile(ctx, "lib/REPL-startup.py", py.CompileOpts{}, replCtx.Module) | ||
if err == nil { | ||
cli.RunREPL(replCtx) | ||
} | ||
|
||
} else { | ||
_, err = py.RunFile(ctx, pyFile, py.CompileOpts{}, nil) | ||
} | ||
|
||
if err != nil { | ||
py.TracebackDump(err) | ||
} | ||
|
||
return err | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"flag" | ||
"os" | ||
"os/exec" | ||
"path/filepath" | ||
"testing" | ||
) | ||
|
||
const embeddingTestOutput = "testdata/embedding_out_golden.txt" | ||
|
||
var regen = flag.Bool("regen", false, "regenerate golden files") | ||
|
||
func TestEmbeddedExample(t *testing.T) { | ||
|
||
tmp, err := os.MkdirTemp("", "go-python-embedding-") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
defer os.RemoveAll(tmp) | ||
|
||
exe := filepath.Join(tmp, "out.exe") | ||
cmd := exec.Command("go", "build", "-o", exe, ".") | ||
err = cmd.Run() | ||
if err != nil { | ||
t.Fatalf("failed to compile embedding example: %v", err) | ||
} | ||
|
||
out := new(bytes.Buffer) | ||
cmd = exec.Command(exe, "mylib-demo.py") | ||
cmd.Stdout = out | ||
|
||
err = cmd.Run() | ||
if err != nil { | ||
t.Fatalf("failed to run embedding binary: %v", err) | ||
} | ||
|
||
testOutput := out.Bytes() | ||
|
||
flag.Parse() | ||
if *regen { | ||
err = os.WriteFile(embeddingTestOutput, testOutput, 0644) | ||
if err != nil { | ||
t.Fatalf("failed to write test output: %v", err) | ||
} | ||
} | ||
|
||
mustMatch, err := os.ReadFile(embeddingTestOutput) | ||
if err != nil { | ||
t.Fatalf("failed read %q", embeddingTestOutput) | ||
} | ||
if !bytes.Equal(testOutput, mustMatch) { | ||
t.Fatalf("embedded test output did not match accepted output from %q", embeddingTestOutput) | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
print(''' | ||
Welcome to a gpython embedded example, | ||
where your wildest Go-based python dreams come true!''') | ||
|
||
# This is a model for a public/user-side script that you or users would maintain, | ||
# offering an open canvas to drive app behavior, customization, or anything you can dream up. | ||
# | ||
# Modules you offer for consumption can also serve to document such things. | ||
from mylib import * | ||
|
||
springBreak = Vacation("Spring Break", Stop("Miami, Florida", 7), Stop("Mallorca, Spain", 3)) | ||
springBreak.AddStops(Stop("Ibiza, Spain", 14), Stop("Monaco", 12)) | ||
springBreak.PrintItinerary() | ||
|
||
print("\nI bet %s will be the best!\n" % springBreak.GetStop(4).Get()[0]) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.