Search code examples
pythonpython-idle

Python IDLE running code differently than other IDEs


I'm trying to get threading to work with a Socket network to accept clients. I had that working fine, but now I have discovered an issue.

Here is the code:

clients = []

def myFunction():    #Not too relevant I think
    server.listen(0)
    conn, addr = server.accept()
    print(conn)
    clients.append(conn, addr)
    threading.Thread(myFunction)

threading.Thread(myFunction)
input("Hit enter to finish...")
print(clients)

Now this should return something like this, which it does on all the IDEs I have tried (PyCharm, Sublime text editor, etc.):

Hit enter to finish...
*2 users connect*
192.168.0.5 # this is the contents of conn
192.168.0.12
*hit enter*
192.168.0.5, 192.168.0.12

However, in Python's own IDLE, the threading seems unable to print anything until I press Enter, with the exact same code, like so:

Hit enter to finish...
*2 users connect*
*hit enter*
192.168.0.5
192.168.0.12
192.168.0.5, 192.168.0.12

This isn't what I want because my code will run in Python IDLE once its finished, so it needs to work here because of this.


Solution

  • As IDLE's name implies, it is primarily a development (and learning) environment. It is aimed especially at beginners. Use for running finished code is at best secondary, and is usually not an advantage.

    The IDLE Doc chapter, which can be viewed in IDLE itself with Help => IDLE Help, has a subsection (3.3) IDLE-console differences. It begins

    With rare exceptions, the result of executing Python code with IDLE is intended to be the same as executing the same code in a console window. However, the different interface and operation occasionally affect visible results.

    The big difference in operation is that your code is executed in a separate Python process, with standard input and output going through a socket connection. This means that all stdout output from your program goes through IDLE code, which inserts it in a tk Text widget, rather than being sent directly to the OS screen manager.

    In the case of input(), IDLE stops displaying output until after the the user hits return. (This is true even with an empty prompt.) I consider this an improvement over having output splattered in the middle of user input. Your code cannot run as is, but the following does.

    import threading, time

    def myFunction():
        time.sleep(1)
        print('Interruption from thread')
    
    thread = threading.Thread(target=myFunction)
    thread.start()
    s =input("Hit enter to finish...")
    print(s)
    

    In IDLE 3.7.0b3 on Win10, I see something like

    Hit enter to finish...skjfsjflsjfljsflsfjls
    Interruption from threadskjfsjflsjfljsflsfjls
    

    (I don't know why the '\n' after 'thread' is suppressed.) In Command Prompt I see

    Hit enter to finish...ksjfkjsInterruption from thread
    fjsfjsfkjsfljksfjkfs
    ksjfkjsfjsfjsfkjsfljksfjkfs
    

    The same issue occurs when inputting code after >>>:. Change my code to

    import threading, time
    
    def myFunction():
        time.sleep(2)
        print('Interruption from thread')
    
    thread = threading.Thread(target=myFunction)
    thread.start()
    

    With IDLE:

    >>> Interruption from thread
    if a = 3:
    

    In Command Prompt entering the same header with the same timing:

    C:\Users\Terry>python -i -m a.tem
    >>> if aInterruption from thread
     = 3
    

    If I better understood the relevant IDLE code, I would have the interrupt line inserted on a line before the prompt. I might also do the same during input(). Fortunately, output from threads or async tasks is not common, especially for beginners.

    ADDENDUM: If one runs IDLE from a command line with python -m idlelib -n it runs in one process and thread output is not blocked. I don't know if other issues will arise in this mode (which is not currently tested).

    We (IDLE maintainers) have agreed that the blocking should be stopped in normal, two process mode and have a idea of why it happens.