Scoping bugs in an embedded Python interpreter - Wizards please

Discussion in 'Python' started by morris.slutsky@gmail.com, Sep 29, 2006.

  1. Guest

    So every now and then I like to mess around with hobby projects - I
    often end up trying to write an OpenGL video game. My last attempt
    aborted due to the difficulty of automating game elements and creating
    a good level editor - I basically needed a scripting language to
    control the C modules of the game and, after a half-assed attempt or
    two to make my own, I just gave up. So naturally this seems like a job
    for Python. Embedding Python into an OpenGL skeleton just seemed like
    a great place to start for my next project. I can write what I need to
    in C, and tie it all together with Python, the games "main loop" itself
    doesn't even need to be in C, I can test things as I go, can reuse
    rendering code for game and level editing applications with great ease,
    Python just seems like a wonderful way to go.

    And it is wonderful! I can just bring up an OpenGL window now, there's
    a console in there, I can type interactive commands in there and they
    get fed into a python interpreter, I can even type stuff like
    glBegin(gl.LINES); glColor()...glVertex()....glEnd() and see stuff
    appear on the screen, it's really amazing and lots of fun. I am sure
    that someday I can be calling C functions like RenderGame, MoveCamera,
    UpdatePhysicsModel(deltaT), all from Python, and life will be good.
    Maybe I can bring bits of my last game in, piece by piece, and tie it
    all together.

    I'm doing all this on Windows, using Microsoft Visual C++. Which is a
    nice compiler, and as an academic I get it free, always a bonus, and I
    can put Python code into resources compiled into the executable and run
    it the same way as I handle interactive commands (being sure to strip
    out all 0x0D characters because for some reason Python believes that
    the One True Line Terminator is 0x0A) and it's all good, it's really
    great.

    The embedding - I'm doing it the way I've seen in web FAQs and the
    Python documentation. I handle output by creating an object "myIO"
    with a "write()" method and having Python start up with "import sys;
    import myIO; sys.stdout = myIO; sys.stderr = myIO" and C gets magically
    called to display Python's output on my OpenGL console, it's grand!
    And I just run all the Python statements, interactive or from
    resources, by calling Py_CompileString() on the string containing
    python code and then, if there are no errors, calling PyEval_EvalCode.
    If I'm running interactive I check for an "unexpected EOF" error just
    like I saw in some FAQ and if I get one I just display a continuation
    prompt and keep accumulating interactive input until I get a blank
    line.... it looks just like the interactive Python you get from a
    command line, it's just in my OpenGL console, which totally rules.

    But .... I'm suffering from serious scoping bugs. I hope someone here
    can help me with them.

    First of all, if I type in something like;

    def f(x):
    if x==1:
    return x
    else:
    return x * f(x-1)

    and then go
    print f(5)

    I get an error. It says 'global name 'f' is not defined'. So
    recursion won't work because of some odd scoping bug.

    Similarly, one of my Python startup files looks like this:

    class gl:
    .....
    POINTS = 0x0000
    LINES = 0x0001
    LINE_LOOP = 0x0002
    LINE_STRIP = 0x0003
    TRIANGLES = 0x0004

    Well, I can't do a "global gl" statement in any function or I get the
    same error. I end up having to pass the "gl" object down and down and
    down, just so I can type glBegin(gl.POINTS) or something, from within a
    function. And I know that this just can't be proper behavior.

    Did I screw up my scoping somehow? How can I fix this? Is there some
    way to call the interpreter that I don't know how to do?

    I appeal to a wizard to help me with this small, but very annoying,
    issue with an otherwise beautiful language.
     
    , Sep 29, 2006
    #1
    1. Advertising

  2. wrote:

    > But .... I'm suffering from serious scoping bugs. I hope someone here
    > can help me with them.
    >
    > First of all, if I type in something like;
    >
    > def f(x):
    > if x==1:
    > return x
    > else:
    > return x * f(x-1)
    >
    > and then go
    > print f(5)
    >
    > I get an error. It says 'global name 'f' is not defined'. So
    > recursion won't work because of some odd scoping bug.


    looks like the globals are all messed up. it would help to see the
    actual C code.

    </F>
     
    Fredrik Lundh, Sep 29, 2006
    #2
    1. Advertising

  3. Guest

    the actual C code - Re: Scoping bugs in an embedded Python interpreter - Wizards please

    Fredrik Lundh wrote:
    > wrote:
    >
    > > But .... I'm suffering from serious scoping bugs. I hope someone here
    > > can help me with them.
    > >
    > > First of all, if I type in something like;
    > >
    > > def f(x):
    > > if x==1:
    > > return x
    > > else:
    > > return x * f(x-1)
    > >
    > > and then go
    > > print f(5)
    > >
    > > I get an error. It says 'global name 'f' is not defined'. So
    > > recursion won't work because of some odd scoping bug.

    >
    > looks like the globals are all messed up. it would help to see the
    > actual C code.
    >
    > </F>


    Thanks!

    I initialize the interpreter like this:


    static PyObject *glb, *loc;

    void startPython() {
    Py_Initialize();
    loc = PyDict_New();
    glb = PyDict_New();
    PyDict_SetItemString (glb, "__builtins__", PyEval_GetBuiltins ());

    Py_InitModule("myIO", myIOMethods);
    ...... other modules initialization ......

    executeFromResource(IDR_STARTUP_PY);
    ....... other startup scripts ........
    }

    I pretty much do the same thing for executing text resources or for
    interactive commands - (and get the same bug either way) - actual code
    from executeFromResource follows ....


    int executeFromResource(int nResourceID) {
    PyObject * src, *exception, *value, *traceback, *object, *result;
    ......miscellaneous Win32 stuff to capture resource from ID
    ......and to strip out 0x0D characters and add NULL terminator.
    ......char * "no0x0D" points to executable Python text
    ......msg is something like <<resource #103>>

    src = Py_CompileString(no0x0D, msg, Py_file_input);

    free(no0x0D);

    if (src != NULL) {
    /* it compiled. run it! */
    result = PyEval_EvalCode ((PyCodeObject *)src, glb, loc);
    if (PyErr_Occurred()) PyErr_Print();
    Py_XDECREF(result);
    Py_XDECREF(src);
    return 1;
    }
    /* report whatever error we got */
    if (nResourceID != IDR_STARTUP_PY)
    {
    /* report it to the console */
    PyErr_Print();
    PyErr_Clear();
    } else {
    /* if startup script dies, we have no console */
    PyErr_Fetch (&exception, &value, &traceback);
    PyArg_ParseTuple (value, "sO", &msg, &object);
    PyErr_Clear();
    Py_XDECREF (exception);
    Py_XDECREF(value);
    Py_XDECREF(traceback);
    outputLogDialog("Error in Python startup\r\n");
    outputLogDialog(msg);
    outputLogDialog("\r\n");
    }
    return 0;
    }

    I had figured that referencing PyObject * glb and * loc was sufficient
    to provide proper variable scoping. Am I missing something here? I
    must be.
     
    , Sep 29, 2006
    #3
  4. Guest

    Re: the actual C code - Re: Scoping bugs in an embedded Python interpreter - Wizards please

    FOUND IT!

    http://mail.python.org/pipermail/python-list/1999-June/005833.html

    So I'm supposed to only have ONE dictionary, 'glb', and forget the
    'loc' for locals.

    Just call PyRun(...glb,glb)....

    Seeing as this was a topic of discussion 7 years ago, maybe it ought to
    be in the "extending and embedding" manual ... well thanks everyone who
    read this.
     
    , Oct 1, 2006
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Charlie DeTar

    embedded python and interpreter threads

    Charlie DeTar, Dec 7, 2004, in forum: Python
    Replies:
    2
    Views:
    691
    Charlie DeTar
    Dec 7, 2004
  2. Replies:
    3
    Views:
    786
    Ziga Seilnacht
    Jan 3, 2007
  3. Guest
    Replies:
    1
    Views:
    355
    Guest
    Mar 16, 2007
  4. Josef 'Jupp' Schugt

    Still use 'ruby-bugs' for Ruby bugs?

    Josef 'Jupp' Schugt, Nov 4, 2004, in forum: Ruby
    Replies:
    2
    Views:
    181
    Tom Copeland
    Nov 4, 2004
  5. Charlton Wang
    Replies:
    5
    Views:
    199
    Charlton Wang
    Dec 7, 2008
Loading...

Share This Page