Skip to content
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

Implement Py_BuildValue #59

Open
elbaro opened this issue Jan 16, 2018 · 4 comments
Open

Implement Py_BuildValue #59

elbaro opened this issue Jan 16, 2018 · 4 comments

Comments

@elbaro
Copy link

@elbaro elbaro commented Jan 16, 2018

Py_BuildValue is not implemented.

func Py_BuildValue(format string, args ...interface{}) *PyObject {
	return nil
}

Example:
f(7,8,9) =

values := python.PyTuple_New(3)
python.PyTuple_SET_ITEM(values, 0, python.PyInt_FromLong(7))
python.PyTuple_SET_ITEM(values, 1, python.PyInt_FromLong(8))
python.PyTuple_SET_ITEM(values, 2, python.PyInt_FromLong(9))
f.CallObject(values)

should be possible with

values := python.Py_BuildValue("(i,i,i)", 7, 8, 9)
f.CallObject(values)
@sbinet
Copy link
Owner

@sbinet sbinet commented Jan 19, 2018

@elbaro, unfortunately, cgo doesn't handle C functions that are variadic (IIRC).

so, essentially, one would need to implement Py_BuildValue in terms of e.g. PyTuple_New + PyTuple_SET_ITEM.
and, for this to work, one would need to also implement a parser for the Py_BuildValue(format) string to infer the tuple size and the various types for the elements of that tuple:

that said that could be done. PR accepted :P

@sbinet
Copy link
Owner

@sbinet sbinet commented Jan 19, 2018

(note that, according to Python2 C-API Py_BuildValue doesn't always return a slice, so this should also be taken care of...)

@icholy
Copy link
Contributor

@icholy icholy commented Jun 14, 2019

What about a hacky solution where there are a bunch of C wrapping functions with a fixed number of parameters. This code is obviously wrong, but it gets the idea across:

PyObject* Py_BuildValue_1(const char *format, PyObject* a1) {
  return Py_BuildValue(format, a1);
}

PyObject* Py_BuildValue_2(const char *format, PyObject* a1, PyObject* a2) {
  return Py_BuildValue(format, a1, a2);
}

PyObject* Py_BuildValue_3(const char *format, PyObject* a1, PyObject* a2, PyObject* a3) {
  return Py_BuildValue(format, a1, a2, a3);
}
func Py_BuildValue(format string, args ...*PyObject) *PyObject {
  switch len(args) {
  case 1:
    return C.Py_BuildValue_1(format, args[0])
  case 2:
    return C.Py_BuildValue_2(format, args[0], args[1])
  case 3:
    return C.Py_BuildValue_3(format, args[0], args[1], args[3])
  default:
    return Py_None
  }
}
@sbinet
Copy link
Owner

@sbinet sbinet commented Jun 14, 2019

SGTM.
that's actually what I did there:
https://github.com/sbinet/go-python/blob/master/go-python.c#L16 for PyObject_CallFunction

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
3 participants
You can’t perform that action at this time.