Problem with C-API

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • John Dean

    #1

    Problem with C-API

    Hi

    I spent the whole of yesterday trying the get the following C code to
    execute

    PyRun_String("d ef title();", Py_file_input, dict, dict);
    PyRun_String("\ treturn 'Foo Bar'", Py_file_input, dict, dict);
    PyRun_String("x = title()", Py_file_input, dict, dict);
    PyObject * result = PyRun_String("p rint x", Py_file_input, dict, dict);
    printf( "The result is %s\n", PyObject_AsStri ng( result );

    Each line throws an error.

    Could somebody tell what is wrong with the above code.

    Here below is the output from my test app

    Starting Test ......

    The file "testtitle" is open for reading

    The variable codeStrings contains

    Line 0 def title()
    Line 1 return "Foo Bar"

    The variable scriptText contains

    def title()
    return "Foo Bar"

    The variable tempList contains

    Line 0 testtitle
    Line 1 title

    Module Name is testtitle

    Function Name is title

    The variable functionCode contains

    def title()
    return "Foo Bar"

    Python initialized successfully

    Module object successfully created

    Dict object successfully created

    Failed to create a Result object.

    The title of the this task is <nil>

    --
    Best Regards
    John
  • Diez B. Roggisch

    #2
    Re: Problem with C-API

    John Dean wrote:
    [color=blue]
    > Hi
    >
    > I spent the whole of yesterday trying the get the following C code to
    > execute
    >
    > PyRun_String("d ef title();", Py_file_input, dict, dict);[/color]
    ^^^^^^^^^^^

    Try using a colon here....
    [color=blue]
    > PyRun_String("\ treturn 'Foo Bar'", Py_file_input, dict, dict);
    > PyRun_String("x = title()", Py_file_input, dict, dict);
    > PyObject * result = PyRun_String("p rint x", Py_file_input, dict, dict);
    > printf( "The result is %s\n", PyObject_AsStri ng( result );[/color]


    Overall it seems to me that ther must be a better way to do such a thing -
    even in C. AFAIK it supports multiline-stringliterals. Why don't you do
    something like this:

    script = "\
    def foo():\n\
    return 'FooBar'\n\
    x = title()\n\
    print x\n"

    And then read that script line by line, feeding it to the parser. Or maybe
    the parser even groks that string at once - don't know that.


    Diez

    Comment

    • Duncan Booth

      #3
      Re: Problem with C-API

      John Dean wrote:
      [color=blue]
      > PyRun_String("d ef title();", Py_file_input, dict, dict);
      > PyRun_String("\ treturn 'Foo Bar'", Py_file_input, dict, dict);
      > PyRun_String("x = title()", Py_file_input, dict, dict);
      > PyObject * result = PyRun_String("p rint x", Py_file_input, dict, dict);
      > printf( "The result is %s\n", PyObject_AsStri ng( result );
      >
      > Each line throws an error.[/color]

      Please don't paraphrase your code when asking questions such as this. The
      code above doesn't even compile (unmatched parentheses) so any response
      must be a guess as to which parts were wrong in your original code and
      which errors you introduced just for the posting.

      Each call to PyRun_String is independant. You seem to think you can call
      the function with part of your source code and then continue with more of
      the source in another call. You cannot.

      Try concatenating the lines together to at least make complete statements.
      Also make sure to handle the result from every call to PyRun_String: check
      it for null, if it is null you should format and print the error message.

      The following is your code rewritten as a working program. When you run it,
      it will tell you about the syntax error in your Python code. Fix that and
      you will see your program output.

      #include <python.h>

      void run() {
      PyObject *dict = PyDict_New();
      PyObject *result;
      if (dict==NULL) {
      PyErr_Print();
      return;
      }

      result = PyRun_String("d ef title();\n\tret urn 'Foo Bar'\n",
      Py_file_input, dict, dict);
      if (result==NULL) {
      PyErr_Print();
      return;
      } else {
      Py_DECREF(resul t);
      }

      result = PyRun_String("x = title()", Py_file_input, dict, dict);
      if (result==NULL) {
      PyErr_Print();
      return;
      } else {
      Py_DECREF(resul t);
      }

      result = PyRun_String("p rint x", Py_file_input, dict, dict);
      if (result==NULL) {
      PyErr_Print();
      return;
      } else {
      PyObject *rString = PyObject_Str(re sult);
      if (rString==NULL) {
      Py_DECREF(resul t);
      PyErr_Print();
      return;
      }

      printf( "The result is %s\n", PyString_AsStri ng(rString));
      Py_DECREF(rStri ng);
      Py_DECREF(resul t);
      }
      }

      int main(int argc, char **argv) {
      Py_Initialize() ;
      run();
      }

      Comment

      • John Dean

        #4
        Re: Problem with C-API

        Hi Duncan

        Your version of the app works apart from this part

        .....
        .....

        else {
        PyObject *rString = PyObject_Str(re sult);
        if (rString==NULL) {
        Py_DECREF(resul t);
        PyErr_Print();
        return;
        }

        printf( "The result is %s\n", PyString_AsStri ng(rString));
        Py_DECREF(rStri ng);
        Py_DECREF(resul t);
        }
        }

        The result of the printf state is: "The result is None"


        result = PyRun_String("p rint x", Py_file_input, dict, dict);

        The above line of code displays the value returned from the title()
        function. My problem is I need to be able to cature the return value because
        in the real application it will be displayed in a Process Log Widget. Also
        the real scripts will be much longer.

        I have not had a problem writing Python extensions, but when it comes to
        embedded Python I just see how to get my code to work.

        Any further help would be greatly appreciated

        --
        Best Regards
        John

        Comment

        • John Dean

          #5
          Re: Problem with C-API

          Hi

          Duncan's example worked to a point. The line PyRun_String( "print x",
          Py_file_input, dict, dict); print out the contents of x, but I don't want to
          print x out. I want to be able to grab whateven the variable x contains so
          that I can pass it on for further processing by the C++ application.

          BTW this is only a test case. The real scripts are much bigger. I must say
          the documentation is not of much help and there are no books or articles
          covering embedding Python in any detail. What there is is very much out of
          date.

          --
          Best Regards
          John

          Comment

          • Fredrik Lundh

            #6
            Re: Problem with C-API

            John Dean wrote:
            [color=blue]
            > Duncan's example worked to a point. The line PyRun_String( "print x",
            > Py_file_input, dict, dict); print out the contents of x, but I don't want to
            > print x out. I want to be able to grab whateven the variable x contains so
            > that I can pass it on for further processing by the C++ application.[/color]

            a better approach is to combine embedding and extending, and let the em-
            bedded code use your extension to talk to your program.

            if you want your program to access x, let the embedded script do

            import myapp
            myapp.write(x)

            since you know how to extend Python, implementing write should be trivial.

            if you insist on picking out variables from the embedded script, you can use
            the same approach as when you want to pull out variables from code you've
            exec'ed: run the code in a namespace dictionary, and extract the data from
            the dictionary after you've run the code. i.e.

            g = {}
            exec code in g
            x = g["x"]

            becomes

            PyObject *g, *x;
            g = PyDict_New();
            PyDict_SetItemS tring(g, "__builtins __", PyEval_GetBuilt ins());
            PyRun_String(my code, Py_file_input, g, NULL);
            x = PyDict_GetItemS tring(g, "x");
            Py_DECREF(g);

            (the SetItemString call is probably not needed in all cases)
            [color=blue]
            > BTW this is only a test case. The real scripts are much bigger. I must say
            > the documentation is not of much help and there are no books or articles
            > covering embedding Python in any detail. What there is is very much out of
            > date.[/color]

            well, I'm getting a bit tired of all this "if it's not published within the last
            few weeks, it's out of date" nonsense that people keep using as an excuse
            for procrastination . The Python C API is very stable, and the embedding
            and extending basics haven't changed a bit in a decade.

            and "no books" is also wrong; ORA's "Programmin g Python" spends some
            40 pages on embedding only (including examples on how to extract stuff
            from module namespaces). I'm pretty sure it's not the only one.

            </F>



            Comment

            • Duncan Booth

              #7
              Re: Problem with C-API

              John Dean wrote:
              [color=blue]
              > Hi Duncan
              >
              > Your version of the app works apart from this part
              >
              > ....
              > ....
              >
              > else {
              > PyObject *rString = PyObject_Str(re sult);
              > if (rString==NULL) {
              > Py_DECREF(resul t);
              > PyErr_Print();
              > return;
              > }
              >
              > printf( "The result is %s\n", PyString_AsStri ng(rString));
              > Py_DECREF(rStri ng);
              > Py_DECREF(resul t);
              > }
              > }
              >
              > The result of the printf state is: "The result is None"[/color]

              Yes, what did you expect it to be? The result from executing the Python
              code was the value None.
              [color=blue]
              >
              >
              > result = PyRun_String("p rint x", Py_file_input, dict, dict);
              >
              > The above line of code displays the value returned from the title()
              > function. My problem is I need to be able to cature the return value
              > because in the real application it will be displayed in a Process Log
              > Widget. Also the real scripts will be much longer.
              >
              > I have not had a problem writing Python extensions, but when it comes
              > to embedded Python I just see how to get my code to work.
              >
              > Any further help would be greatly appreciated
              >[/color]
              If you want the value of x, then pick it out of the dictionary:

              {
              PyObject *x = PyDict_GetItemS tring(dict, "x");
              PyObject *rString = PyObject_Str(x) ;
              printf( "x is %s\n", PyString_AsStri ng(rString));
              Py_DECREF(rStri ng);
              Py_DECREF(x);
              }
              Py_DECREF(dict) ; // I forgot this one in my original code.

              If you want to embed Python though you really should look at Pyrex. Using
              Pyrex you can all but forget about the Python api, write a Pyrex function
              which is callable directly from C: it calls the Python code and returns the
              C values you want as a result. Also it will handle all the error checking
              and reference counting automatically.

              Comment

              Working...