loader.py 2.33 KB
Newer Older
David Scherer's avatar
David Scherer committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
# Everything is done inside the loader function so that no other names
# are placed in the global namespace.  Before user code is executed,
# even this name is unbound.
def loader():
    import sys, os, protocol, threading, time
    import Remote

##  Use to debug the loading process itself:
##    sys.stdout = open('c:\\windows\\desktop\\stdout.txt','a')
##    sys.stderr = open('c:\\windows\\desktop\\stderr.txt','a')

    # Ensure that there is absolutely no pollution of the global
    # namespace by deleting the global name of this function.
    global loader
    del loader

    # Connect to IDLE
    try:
        client = protocol.Client()
    except protocol.connectionLost, cL:
        print 'loader: Unable to connect to IDLE', cL
        return

    # Connect to an ExecBinding object that needs our help.  If
    # the user is starting multiple programs right now, we might get a
    # different one than the one that started us.  Proving that's okay is
    # left as an exercise to the reader.  (HINT:  Twelve, by the pigeonhole
    # principle)
    ExecBinding = client.getobject('ExecBinding')
    if not ExecBinding:
        print "loader: IDLE does not need me."
        return

    # All of our input and output goes through ExecBinding.
    sys.stdin  = Remote.pseudoIn( ExecBinding.readline )
    sys.stdout = Remote.pseudoOut( ExecBinding.write.void, tag="stdout" )
    sys.stderr = Remote.pseudoOut( ExecBinding.write.void, tag="stderr" )

    # Create a Remote object and start it running.
    remote = Remote.Remote(globals(), ExecBinding)
    rthread = threading.Thread(target=remote.mainloop)
    rthread.setDaemon(1)
    rthread.start()

    # Block until either the client or the user program stops
    user = rthread.isAlive
    while user and client.isAlive():
        time.sleep(0.025)

        if not user():
          user = hasattr(sys, "ready_to_exit") and sys.ready_to_exit
          for t in threading.enumerate():
            if not t.isDaemon() and t.isAlive() and t!=threading.currentThread():
              user = t.isAlive
              break

    # We need to make sure we actually exit, so that the user doesn't get
    #   stuck with an invisible process.  We want to finalize C modules, so
    #   we don't use os._exit(), but we don't call sys.exitfunc, which might
    #   block forever.
    del sys.exitfunc
    sys.exit()

loader()