treeform / genny

Generate a shared library and bindings for many languages.
MIT License
224 stars 9 forks source link

A proc that returns a string seems to be seen as a int in python #30

Closed JohnAD closed 2 years ago

JohnAD commented 2 years ago

I've been impressed by this library. It seems to greatly simplify the interface between nim and python.

Unfortunately, I've been having problems with def procs that return strings.

So, to provide a simplified example, a bindings.nim:

import unicode

import genny

import txtdb

proc joe(): string =
    result = "hello"

exportProcs:
  joe

writeFiles("bindings/generated", "txtdb")
include generated/internal

Examining the internal file:

proc txtdb_joe*(): cstring {.raises: [], cdecl, exportc, dynlib.} =
  joe().cstring

And yet, if I call it from python:

test = dll.txtdb_joe().decode("utf8")

I get:

Traceback (most recent call last):
  File "/home/johnd/Projects/pytxtdb/tests/test_load.py", line 16, in <module>
    result = person_table.create(person_c)
  File "/home/johnd/Projects/pytxtdb/src/txtdb.py", line 40, in create
    test = dll.txtdb_joe().decode("utf8")
AttributeError: 'int' object has no attribute 'decode'

Details:

Running on Pop_OS!, an ubuntu variant. So, using libtxtdb.so. Nim is version 1.4.8. Python is

Python 3.9.5 (default, May 11 2021, 08:20:37) 
[GCC 10.3.0] on linux

genny version is genny [0.1.0]

Thanks for any help you can provide!

guzba commented 2 years ago

Interesting issue. Thanks very much for trying genny and for reporting this issue along with great information so we can reproduce it. Will reply back here with an update soon.

guzba commented 2 years ago

Ok this took a bit longer than I expected to get back to but I do have an update. I am not able to reproduce the issue, but I do know we haven't really documented well how to set things up so there could be many issues along the way. Some things:

nim c -f -d:release --app:lib --gc:arc --tlsEmulation:off --out:txtdb bindings.nim or something like this should be the compile command.

From here, the generated python file does need a tweak to work without the pip set up (which is too much for a simple test). An modified output python file would be:

from ctypes import *
import os, sys

dir = os.path.dirname(os.path.abspath(__file__))
if sys.platform == "win32":
  libName = "txtdb.dll"
elif sys.platform == "darwin":
  libName = "libtxtdb.dylib"
else:
  libName = "libtxtdb.so"
dll = cdll.LoadLibrary(os.path.join(dir, libName))

class txtdbError(Exception):
    pass

def joe():
    result = dll.txtdb_joe().decode("utf8")
    return result

dll.txtdb_joe.argtypes = []
dll.txtdb_joe.restype = c_char_p

test = joe()

print(test)

Notice that I added the print at the bottom, call joe() instead of the dll proc, and changed the dir = at the top to work with file paths. It expects the dll / so to be in the same directory as the python file, and the same directory you are running the python script.

For me, then python txtdb.py prints hello as expected.

I hope this helps and thanks for giving genny a try. As you've noticed, it is pretty cool but also quite new and rough. We'll work through it though as we put more time in on genny.

guzba commented 2 years ago

Closing this just for housekeeping. Please re-open if there is an update.