LottaMe / pylet

A tool to learn python that is inspired by rustlings.
MIT License
0 stars 0 forks source link

Add pylet commands #25

Open LottaMe opened 6 months ago

LottaMe commented 6 months ago

Description

The user should be able to enter commands while running pylet to get a hint (hint) or exit the program (exit) (same as keyboardinterrupt)

LottaMe commented 5 months ago

https://stackoverflow.com/questions/20576960/python-infinite-while-loop-break-on-user-input

LottaMe commented 5 months ago

Inputs without blocking - focus hint

To be able to do thehint command, you need to be able to get an input from the user without it blocking the exercises from runnng.

Ideas:

Threading:

Have a different thread running for the input then for exercise running.

Problems:

-> even more concurrency -> python gets weird with the main thread and it might lead to unexpected bugs that are also hard to test, when introducing more and more threads and processes.

sys.stdin...

Go beyond input statement, which blocks, and go with system level/lower level libraries to code a non-blocking input.

Problems:

-> handled differently on different operating systems -> tries to get lower level with python while still having a high level of abstraction will lead to unexpected bug

Input in exercise.run

Have input() at the end of the exercise, after check_done. This does block it, but at this time the process is done and blocked anyway till it is restarted. If we put the input to only execute if check_done is false, this should not block the program.

Problems:

-> can we handle other commands like this? e.g. exit? -> NO INPUT IN SUBPROCESS

LottaMe commented 5 months ago

More research

After trying out more there are more notes. I have experimented with threading, and while I was successful in getting hint command from the user, I have not managed to have it not block the program to continue. So that the user entering something was required.

I have managed to use pythons open(0) to access the standard input even in a child process and calling it in the exercise.run but it is also blocking the program similarly to threading. I guess terminating the process is not ending the open? But I would have to do more research on this.

with open(0) as stdin:
    result = stdin.readline()
    if "hint" in result:
        print(hint_message)

A couple of ways to go from here:

Look (more) into asyncio and threading.

Threading might not end up working, but I can’t say that for sure without more research. Maybe more interesting would be looking into asyncio, so that the input is asked for asynchronously, which as far as I know can be cancelled in the await. Currently I don’t know much about how this works, but from the little I’ve read it might be useful.

Non blocking input

So from me trying to write or read about non blocking inputs in python I do not like the implementations I saw much. I think they are very unintuitive and would be difficult to understand when reading the code in the future or when someone else is reading the code.

This is a separately written code snippet that works for non blocking input. Something similar might be implemented somewhere in the code, possibly in combination with threading, multiprocessing, asyncio to complete this task.

import sys
import os
import fcntl
import time

fl = fcntl.fcntl(sys.stdin.fileno(), fcntl.F_GETFL)
fcntl.fcntl(sys.stdin.fileno(), fcntl.F_SETFL, fl | os.O_NONBLOCK)

input_received = False
while not input_received:
    print("Waiting for user input")
    try:
        stdin = sys.stdin.read()
        if stdin:
            if "exit" in stdin:
                input_received = True
    except (IOError, TypeError):
        pass
    time.sleep(1)

More multiprocessing :devil:

Okay, I really don’t want to do this for reasons I will go into, but this would probably work, because processes can be terminated so easily. Basically after starting the exercise process, I could start an input process so the two of them are executed at the same time, hints can be printed and every time the exercise process is terminated or the exercise is done, the input process is terminated (if still running).

Now why do I not want to use this.

A lot of these solutions don’t really seem worth it for the feature it adds, especially because I could just add the hint as a comment In the file, so I will switch my focus to other things for now, and keep this issue and the comments for documentation in case I will revisit the task later.