4

I have some Python code that works as expected if I type the commands one-at-a-time using Python's interactive mode. The same code crashes if saved as myscript.py and run as 'C:\Python27\python.exe myscript.py'.

In what ways could running Python code as a script cause it to crash, if the same code works in interactive mode?

This question asks for ways to tell if python is in interactive mode. However, the asker just wants a single, reliable fingerprint of interactive mode. I'd like a list of ways that interactive mode is different, with particular attention to problems this can cause.

For example:

  • sys.path could be different
  • os.getcwd() could be different
  • os.environ could be different
  • All the answers to this question
  • This warning at the beginning of the multiprocessing module documentation

What else could be different between Python's interactive and script mode?

Community
  • 1
  • 1
Andrew
  • 2,842
  • 5
  • 31
  • 49
  • I don't think the issues with sys or os would ever be different, given that both versions (interative versus script) are run in the same context. In other words, from any given directory if you do "python script.py" or "python -i", the cwd, path and environment will be identical. – Bryan Oakley May 11 '12 at 20:20
  • when you say "in iteractive mode" are you talking about running "python -i", or are you talking about running via IDLE? There are definitely some differences between those two. – Bryan Oakley May 11 '12 at 20:25
  • Good question, Bryan Oakley. In this question, I was thinking of `python myscript.py` versus `python -i` and typing the same commands manually. If you're confident about your assertions (cwd, path and envronment will be identical), I'll edit my question to remove my misleading statements. – Andrew May 11 '12 at 20:31
  • Karl Knechtel, I was thinking of 'raises an exception', or something similar. Is that the type of definition you were wondering about? I guess I wasn't thinking of a segfault or crashing out of python or BSOD. – Andrew May 11 '12 at 21:05
  • There are ways to make CPython crash, if you're sufficiently evil, that the implementation can't really do anything about. But what I'm getting at: instead of trying to compile a list of differences, why not show us the code that's crashing and how it's crashing? – Karl Knechtel May 11 '12 at 21:20
  • Ah, excellent point, Karl. The [previous question](http://stackoverflow.com/questions/10525304/program-works-in-idle-but-fails-at-the-command-line) I reference shows some code of mine that's crashing, and how it's crashing. I am very interested in solving that problem. However, I'm also interested in the more general question of how the two cases can differ, and I haven't found good explanations with Google. – Andrew May 11 '12 at 21:28

3 Answers3

4

Threads and Greenlets have different behavior in an interactive environment. The main event loop has to be hacked in some instances.

Greenlet is from the gevent module which is a concurrent task in python. It has an internal context switching separate from Python's (pthread) and the concurrency works really well (in my experience). Some of the issues with Greenlets is that they block on blocking C-system calls and socket interactions if they're not monkey-patched (module in gevent).

The main event-loop needs to be patched in order for the greenlets to work correctly... If you spawn a greenlet in an interactive environment it will not switch contexts and execute, I forgot how off the top of my head how to patch the main event loop (will add later).

Example of failure:

In [1]: from gevent.greenlet import Greenlet

In [2]: def print_hi():
   ...:     print 'hi'
   ...:     

In [3]: print_hi()
hi

In [4]: g = Greenlet(print_hi)

In [5]: g.start()

Edit:

After looking at some of the code on this project here's how we hacked the ipython input hook to use gevent

import sys
import select
import gevent

def stdin_ready():
    infds, outfds, erfds = select.select([sys.stdin], [], [], 0)
    if infds:
        return True
    else:
        return False

def inputhook_gevent():
    try:
        while not stdin_ready():
            gevent.sleep(0.001)
    except KeyboardInterrupt:
        pass

    return 0

# install the gevent inputhook
from IPython.lib.inputhook import inputhook_manager
inputhook_manager.set_inputhook(inputhook_gevent)
inputhook_manager._current_gui = 'gevent'

# First import the embeddable shell class
from IPython.frontend.terminal.embed import InteractiveShellEmbed

Patched Example:

In [6]: def say_hi():
   ...:     print "hi"
   ...:     

In [7]: g = gevent.greenlet.Greenlet(say_hi)

In [8]: g.start()

In [9]: hi  <-- Cursor is here so it printed hi
lukecampbell
  • 14,728
  • 4
  • 34
  • 32
  • This sounds like good information. I don't know what a greenlet is, though. If you elaborate, it would probably educate me. – Andrew May 11 '12 at 20:21
  • Great edit, much more informative. Certainly not anything I suspected. – Andrew May 11 '12 at 20:37
1

It looks like you're interacting with hardware, which brings up the most glaring difference between the REPL and a script:

Commands in a script run immediately as soon as possible, whereas the REPL waits for human input.

That is to say, you are probably having a timing issue where the hardware isn't ready for the next command so soon after executing the previous.

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
  • An excellent point. In the hardware-specific question I reference, I'll try adding time.sleep(1) in between every command. – Andrew May 11 '12 at 20:19
  • Ok, I tried adding `time.sleep(1)` between all the commands in my hardware-related question. The behavior is the same. So, great answer to this question, doesn't seem to solve the other one. – Andrew May 11 '12 at 20:34
0

Take a look at this line

PCO_api = ctypes.oledll.LoadLibrary("SC2_Cam")

If you can use the COMPLETE path for LoadLibrary

lukecampbell
  • 14,728
  • 4
  • 34
  • 32