0

I am trying to create a Python extension that takes arguements. This is my script:

#include <Python.h>

static PyObject * _message(PyObject *self, PyObject *args) {
    char *title, *message;

    if (!PyArg_ParseTuple(args, &title, &message)) 
        return NULL; // Throw an error

    return Py_BuildValue("");
}


static PyMethodDef methods[] = {
    {"Message", (PyCFunction) _message, METH_VARARGS, "Message(title, message) Take a message"},
    {NULL, NULL, 0, NULL} 
};


static struct PyModuleDef functions = {
    PyModuleDef_HEAD_INIT,
    "test", 
    "Take a message", 
    "-1",
    methods 

};

PyMODINIT_FUNC PyInit_test(void) {

    PyObject *module = PyModule_Create(&functions);

    return module;
}

Setup.py:

from setuptools import setup, Extension

module = Extension (
    "test",
    sources = ['test.c'])


setup(
    name = "test",
    version = "1.0",
    description = "Take message input",
    author = "Simon",
    ext_modules = [module])

However when I try to compile it I am left with an error:

C:\Users\Simon\Desktop\PyTest>python setup.py build
running build
running build_ext
building 'test' extension
C:\Program Files (x86)\Microsoft Visual Studio\2017\WDExpress\VC\Tools\MSVC\14.14.26428\bin\HostX86\x86\cl.exe /c /nologo /Ox /W3 /GL /DNDEBUG /MT -IC:\Users\Simon\AppData\Local\Programs\Python\Python36-32\include -IC:\Users\Simon\AppData\Local\Programs\Python\Python36-32\include "-IC:\Program Files (x86)\Microsoft Visual Studio\2017\WDExpress\VC\Tools\MSVC\14.14.26428\include" "-IC:\Program Files (x86)\Windows Kits\NETFXSDK\4.6.1\include\um" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\ucrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\shared" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\um" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\winrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\cppwinrt" /Tctest.c /Fobuild\temp.win32-3.6\Release\test.obj
test.c
test.c(2): warning C4067: unexpected tokens following preprocessor directive - expected a newline
test.c(10): warning C4047: 'function': 'const char *' differs in levels of indirection from 'char **'
test.c(10): warning C4024: 'PyArg_ParseTuple': different types for formal and actual parameter 2
test.c(23): warning C4047: 'initializing': 'Py_ssize_t' differs in levels of indirection from 'char [3]'
test.c(42): warning C4047: 'function': 'const char *' differs in levels of indirection from 'int'
test.c(42): warning C4024: 'PyModule_AddStringConstant': different types for formal and actual parameter 3
C:\Program Files (x86)\Microsoft Visual Studio\2017\WDExpress\VC\Tools\MSVC\14.14.26428\bin\HostX86\x86\link.exe /nologo /INCREMENTAL:NO /LTCG /nodefaultlib:libucrt.lib ucrt.lib /DLL /MANIFEST:EMBED,ID=2 /MANIFESTUAC:NO /LIBPATH:C:\Users\Simon\AppData\Local\Programs\Python\Python36-32\libs /LIBPATH:C:\Users\Simon\AppData\Local\Programs\Python\Python36-32\PCbuild\win32 "/LIBPATH:C:\Program Files (x86)\Microsoft Visual Studio\2017\WDExpress\VC\Tools\MSVC\14.14.26428\lib\x86" "/LIBPATH:C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6.1\lib\um\x86" "/LIBPATH:C:\Program Files (x86)\Windows Kits\10\lib\10.0.17134.0\ucrt\x86" "/LIBPATH:C:\Program Files (x86)\Windows Kits\10\lib\10.0.17134.0\um\x86" test.lib /EXPORT:PyInit_test build\temp.win32-3.6\Release\test.obj /OUT:build\lib.win32-3.6\test.cp36-win32.pyd /IMPLIB:build\temp.win32-3.6\Release\test.cp36-win32.lib
   Creating library build\temp.win32-3.6\Release\test.cp36-win32.lib and object build\temp.win32-3.6\Release\iup.cp36-win32.exp
Generating code
Finished generating code

I am quite sure the rest of my code is correct except for taking the arguments at:

static PyObject * _message(PyObject *self, PyObject *args) {
    char *title, *message;

    if (!PyArg_ParseTuple(args, &title, &message)) 

The extension is created, however when I try to run it, it crashes.

How can I take positional arguments?

Xantium
  • 11,201
  • 10
  • 62
  • 89
  • 1
    The error messages seem instructive. Check the docs on the specific things they mention, like for example PyArg_ParseTuple. – Kenny Ostrom Jun 22 '18 at 15:42
  • 1
    You need to specify the *type* of argument in the second parameter. For example: `if (!PyArg_ParseTuple(args,"zz",&title, &message))`, where `z` indicates a C-style zero delimited string, `"zz"` indicates you have two of them. – cdarke Jun 22 '18 at 15:52
  • @cdarke Yes I've read about, I didn't realise I needed to include one in that argument (but it makes sense). Thank you. – Xantium Jun 22 '18 at 15:57
  • Still getting the `test.c(23): warning C4047: 'initializing': 'Py_ssize_t' differs in levels of indirection from 'char [3]'` error though. – Xantium Jun 22 '18 at 15:59
  • 1
    I missed that, your ` "-1",` should be `-1` in `functions`. – cdarke Jun 22 '18 at 16:10
  • @cdarke Darn that was a daft one, could you please consider leaving an answer that I can accept, It's working now, thank you. :) – Xantium Jun 22 '18 at 16:13
  • 1
    I'm glad you got it working. I've written an answer. – cdarke Jun 22 '18 at 16:18

2 Answers2

1

You need to specify the type of argument in the second parameter. For example:

if (!PyArg_ParseTuple(args,"zz", &title, &message))

where z indicates a C-style zero delimited string, "zz" indicates you have two of them. These are called specifers, and there are many of them, here are some of the most common:

i/I     Signed/unsigned int
d/D     Signed/unsigned double
s       C-style string (char *)
z       C-style string or None
y       bytes object
O       Generic Python object (oh)
O!      Typed Python object (oh!)

Also, your "-1" should be -1 in functions.

cdarke
  • 42,728
  • 8
  • 80
  • 84
0

Did you have looking for disutils ?

This library can run C code and maybe help you. You can get more informations about in this page of the official Python's documentation : https://docs.python.org/3/extending/building.html

Sunchock
  • 361
  • 4
  • 14
  • Thank you for you answer, but I think you have it the wrong way around. It's setuptools that is recommended reading [this answer](https://stackoverflow.com/questions/25337706/setuptools-vs-distutils-why-is-distutils-still-a-thing) – Xantium Jun 22 '18 at 16:11
  • On your screenshot, yours compiler is telling you that he met unknown tokens. This is a mistake and I still thinking it's because you're trying to parse your C file as a Python file but the script still running and generate an executable It's crashes because it's probably corrupted by parsing failures. There is an example with C language importation in documentation over Python v3.5.4, I think you should look at it. – Sunchock Jun 22 '18 at 16:24
  • It's not my down-vote, here is the same documentation in English: https://docs.python.org/3/extending/building.html if you want to edit it in. I will read it. Thank you. – Xantium Jun 22 '18 at 18:03
  • Thanks for your kindness, I edited my post because I realized my way isn't the best for you, my mistake ! – Sunchock Jun 22 '18 at 20:36