Skip to content

Commit

Permalink
Merge pull request #3 from cpunion/update
Browse files Browse the repository at this point in the history
Setter/Getter/members/Testing
  • Loading branch information
cpunion authored Nov 1, 2024
2 parents 3129ff5 + e7dbd10 commit 7ac7a2c
Show file tree
Hide file tree
Showing 16 changed files with 1,699 additions and 245 deletions.
215 changes: 214 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,217 @@ func main() {

### Define Python Objects

To be written.
See [autoderef/foo](_demo/autoderef/foo).

```go
type Point struct {
X float64
Y float64
}

func (p *Point) init(x, y float64) {
p.X = x
p.Y = y
}

func (p *Point) Print() {
fmt.Printf("Point(%f, %f)\n", p.X, p.Y)
}

func (p *Point) Distance() float64 {
return p.X * p.Y
}

// Move method for Point
func (p *Point) Move(dx, dy float64) {
p.X += dx
p.Y += dy
}

func Add(a, b int) int {
return a + b
}

func InitFooModule() gp.Module {
m := gp.CreateModule("foo")
// Add the function to the module
m.AddMethod("add", Add, "(a, b) -> float\n--\n\nAdd two integers.")
// Add the type to the module
gp.AddType[Point](m, (*Point).init, "Point", "Point objects")
return m
}
```

Call foo module from Python and Go.

```go
package main

import (
"fmt"
"runtime"

gp "github.com/cpunion/go-python"
"github.com/cpunion/go-python/_demo/autoderef/foo"
pymath "github.com/cpunion/go-python/math"
)

func Main1() {
gp.RunString(`
import foo
point = foo.Point(3, 4)
print("dir(point):", dir(point))
print("x:", point.x)
print("y:", point.y)
print("distance:", point.distance())
point.move(1, 2)
print("x:", point.x)
print("y:", point.y)
print("distance:", point.distance())
point.print()
`)
}

func Main2(fooMod gp.Module) {
sum := fooMod.Call("add", gp.MakeLong(1), gp.MakeLong(2)).AsLong()
fmt.Printf("Sum of 1 + 2: %d\n", sum.Int64())

dict := fooMod.Dict()
Point := dict.Get(gp.MakeStr("Point")).AsFunc()

point := Point.Call(gp.MakeLong(3), gp.MakeLong(4))
fmt.Printf("dir(point): %v\n", point.Dir())
fmt.Printf("x: %v, y: %v\n", point.GetAttr("x"), point.GetAttr("y"))

distance := point.Call("distance").AsFloat()
fmt.Printf("Distance of 3 * 4: %f\n", distance.Float64())

point.Call("move", gp.MakeFloat(1), gp.MakeFloat(2))
fmt.Printf("x: %v, y: %v\n", point.GetAttr("x"), point.GetAttr("y"))

distance = point.Call("distance").AsFloat()
fmt.Printf("Distance of 4 * 6: %f\n", distance.Float64())
point.Call("print")
}

func main() {
gp.Initialize()
defer gp.Finalize()
fooMod := foo.InitFooModule()
gp.GetModuleDict().Set(gp.MakeStr("foo").Object, fooMod.Object)

Main1()
Main2(fooMod)
}
```

### Call gradio

See [gradio](_demo/gradio).

```go
package main

import (
"os"

gp "github.com/cpunion/go-python"
)

/*
import gradio as gr
def update_examples(country):
print("country:", country)
if country == "USA":
return gr.Dataset(samples=[["Chicago"], ["Little Rock"], ["San Francisco"]])
else:
return gr.Dataset(samples=[["Islamabad"], ["Karachi"], ["Lahore"]])
with gr.Blocks() as demo:
dropdown = gr.Dropdown(label="Country", choices=["USA", "Pakistan"], value="USA")
textbox = gr.Textbox()
examples = gr.Examples([["Chicago"], ["Little Rock"], ["San Francisco"]], textbox)
dropdown.change(update_examples, dropdown, examples.dataset)
demo.launch()
*/

var gr gp.Module

func UpdateExamples(country string) gp.Object {
println("country:", country)
if country == "USA" {
return gr.Call("Dataset", gp.KwArgs{
"samples": [][]string{{"Chicago"}, {"Little Rock"}, {"San Francisco"}},
})
} else {
return gr.Call("Dataset", gp.KwArgs{
"samples": [][]string{{"Islamabad"}, {"Karachi"}, {"Lahore"}},
})
}
}

func main() {
if len(os.Args) > 2 {
// avoid gradio start subprocesses
return
}

gp.Initialize()
gr = gp.ImportModule("gradio")
fn := gp.CreateFunc(UpdateExamples,
"(country, /)\n--\n\nUpdate examples based on country")
// Would be (in the future):
// fn := gp.FuncOf(UpdateExamples)
demo := gp.With(gr.Call("Blocks"), func(v gp.Object) {
dropdown := gr.Call("Dropdown", gp.KwArgs{
"label": "Country",
"choices": []string{"USA", "Pakistan"},
"value": "USA",
})
textbox := gr.Call("Textbox")
examples := gr.Call("Examples", [][]string{{"Chicago"}, {"Little Rock"}, {"San Francisco"}}, textbox)
dataset := examples.GetAttr("dataset")
dropdown.Call("change", fn, dropdown, dataset)
})
demo.Call("launch")
}
```

### Call matplotlib

See [plot](_demo/plot).

```go
package main

import gp "github.com/cpunion/go-python"

type plt struct {
gp.Module
}

func Plt() plt {
return plt{gp.ImportModule("matplotlib.pyplot")}
}

func (m plt) Plot(args ...any) gp.Object {
return m.Call("plot", args...)
}

func (m plt) Show() {
m.Call("show")
}

func main() {
gp.Initialize()
defer gp.Finalize()
plt := Plt()
plt.Plot(gp.MakeTuple(5, 10), gp.MakeTuple(10, 15), gp.KwArgs{"color": "red"})
plt.Show()
}
```
117 changes: 117 additions & 0 deletions _demo/autoderef/autoderef.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package main

import (
"fmt"
"runtime"

gp "github.com/cpunion/go-python"
"github.com/cpunion/go-python/_demo/autoderef/foo"
pymath "github.com/cpunion/go-python/math"
)

func main() {
gp.Initialize()
defer gp.Finalize()
fooMod := foo.InitFooModule()
gp.GetModuleDict().Set(gp.MakeStr("foo").Object, fooMod.Object)

Main1(fooMod)
Main2()
Main3()
}

func Main1(fooMod gp.Module) {
fmt.Printf("=========== Main1 ==========\n")
sum := fooMod.Call("add", gp.MakeLong(1), gp.MakeLong(2)).AsLong()
fmt.Printf("Sum of 1 + 2: %d\n", sum.Int64())

dict := fooMod.Dict()
Point := dict.Get(gp.MakeStr("Point")).AsFunc()

point := Point.Call(gp.MakeLong(3), gp.MakeLong(4))
fmt.Printf("dir(point): %v\n", point.Dir())
fmt.Printf("x: %v, y: %v\n", point.GetAttr("x"), point.GetAttr("y"))

distance := point.Call("distance").AsFloat()
fmt.Printf("Distance of 3 * 4: %f\n", distance.Float64())

point.Call("move", gp.MakeFloat(1), gp.MakeFloat(2))
fmt.Printf("x: %v, y: %v\n", point.GetAttr("x"), point.GetAttr("y"))

distance = point.Call("distance").AsFloat()
fmt.Printf("Distance of 4 * 6: %f\n", distance.Float64())
point.Call("print")
}

func Main2() {
fmt.Printf("=========== Main2 ==========\n")
gp.RunString(`
import foo
point = foo.Point(3, 4)
print("dir(point):", dir(point))
print("x:", point.x)
print("y:", point.y)
print("distance:", point.distance())
point.move(1, 2)
print("x:", point.x)
print("y:", point.y)
print("distance:", point.distance())
point.print()
`)
}

func Main3() {
pythonCode := `
def allocate_memory():
return bytearray(10 * 1024 * 1024)
def memory_allocation_test():
memory_blocks = []
for i in range(10):
memory_blocks.append(allocate_memory())
print('Memory allocation test completed.')
return memory_blocks
for i in range(10):
memory_allocation_test()
`

mod := gp.ImportModule("__main__")
gbl := mod.Dict()
code := gp.CompileString(pythonCode, "<string>", gp.FileInput)
_ = gp.EvalCode(code, gbl, gp.Nil().AsDict())
for i := 0; i < 10; i++ {
result := gp.EvalCode(code, gbl, gp.Nil().AsDict())
if result.Nil() {
fmt.Printf("Failed to execute Python code\n")
return
}
fmt.Printf("Iteration %d in python\n", i+1)
}

memory_allocation_test := mod.GetFuncAttr("memory_allocation_test")

for i := 0; i < 100; i++ {
// 100MB every time
memory_allocation_test.Call()
fmt.Printf("Iteration %d in go\n", i+1)
runtime.GC()
}

for i := 1; i <= 100000; i++ {
println(i)
f := gp.MakeFloat(float64(i))
r := pymath.Sqrt(f)
b := r.IsInteger()
var _ bool = b.Bool()
if i%10000 == 0 {
fmt.Printf("Iteration %d in go\n", i)
}
}

gp.Finalize()
fmt.Printf("Done\n")
}
50 changes: 50 additions & 0 deletions _demo/autoderef/foo/foo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package foo

/*
#cgo pkg-config: python3-embed
#include <Python.h>
*/
import "C"

import (
"fmt"

gp "github.com/cpunion/go-python"
)

type Point struct {
X float64
Y float64
}

func (p *Point) init(x, y float64) {
p.X = x
p.Y = y
}

func (p *Point) Print() {
fmt.Printf("Point(%f, %f)\n", p.X, p.Y)
}

func (p *Point) Distance() float64 {
return p.X * p.Y
}

// Move method for Point
func (p *Point) Move(dx, dy float64) {
p.X += dx
p.Y += dy
}

func Add(a, b int) int {
return a + b
}

func InitFooModule() gp.Module {
m := gp.CreateModule("foo")
// Add the function to the module
m.AddMethod("add", Add, "(a, b) -> float\n--\n\nAdd two integers.")
// Add the type to the module
gp.AddType[Point](m, (*Point).init, "Point", "Point objects")
return m
}
4 changes: 2 additions & 2 deletions _demo/gradio/gradio.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ func main() {

gp.Initialize()
gr = gp.ImportModule("gradio")
fn := gp.FuncOf(UpdateExamples,
"update_examples(country, /)\n--\n\nUpdate examples based on country")
fn := gp.CreateFunc(UpdateExamples,
"(country, /)\n--\n\nUpdate examples based on country")
// Would be (in the future):
// fn := gp.FuncOf(UpdateExamples)
demo := gp.With(gr.Call("Blocks"), func(v gp.Object) {
Expand Down
Loading

0 comments on commit 7ac7a2c

Please sign in to comment.