Skip to content
This repository has been archived by the owner on Jul 24, 2023. It is now read-only.

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 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 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 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 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 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 subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants