Override raw_input to get answer from remote client - python

I'm trying to override the standard raw_input so I can have a "remote raw_input".
What I need is to implement this overriden raw_input so when I use it on my server, it will open a message box in the remote client's computer and wait for his answer. After getting the response, I'll then be able to continue with my program.
I've been searching a lot about how I can do this, but I'm a little lost mostly because I'm new to python.
And I have to do this with raw_input, is that possible? Can someone give me a little guidance?
UPDATE:
One good example of what I'm trying to achieve is how Jupyter handles raw_inputs.
In this notebook I simply run a raw_input, then Jupyter creates a textbox and waits for my answer:
And then after I type my answer it goes on with the code:
So how does Jupyter get 'in the middle' of the raw_input to create a textbox and wait for the user input?

Overriding builtins is, generally, not recommended for a number of reasons. Instead, try something like the following, using receive_input instead of raw_input.
SERVER = 1
CLI = 2
...
config.input_type = CLI # in cli code, or SERVER in server code
...
def receive_input(cfg):
if cfg.input_type == CLI:
return raw_input()
elif cfg.input_type == SERVER:
# retrieve from somewhere else
Jupyter likely scans the AST of the input for raw_input called as a function and replaces that with their implementation.

Related

Docker accepting input to python script

I am simulating an online IDE using docker.
Each time user submits their code, an image will be generated and be run. It is working as expected, however when the code asks for input e.g
print("Begin script")
x = input("Enter your name")
print("you entered")
print(x)
python code to run docker:
container = subprocess.Popen(["docker", "run","-it", "--rm", "--name",imageName,imageName])
I am unable to pass in input to the python script.
It does not even print the prompt "Test input" into terminal
I have tried using docker attach command, and I am enter able to enter into terminal, but it is not sending input to python script
Via comments:
subprocess.run(["docker", "run","-ti", "--rm", "--name",imageName,imageName], capture_output=True)
You're using a function that is described to (emphasis mine)
Run the command described by args. Wait for command to complete, then return a CompletedProcess instance.
You also say
it does not even print the prompt of the input message
This is because you've explicitly told subprocess.run() to capture the output instead of allowing it to be printed to stdout. If you were to print the return value of that call, you'd possibly see the output.
If you just want some static input to be piped to the process and get the output, you could use
proc = subprocess.run(..., input="123\n", capture_output=True)
print(proc.stdout)
to simulate someone entering 123 and a newline.
If you want an interactive experience, you will need to use subprocess.Popen() instead. Wiring the stdin/stdout/stderr pipes is somewhat tricky, especially if you need a TTY-like experience.
I am really sorry that it doesn't answer your question directly, but I am sure it would help.
I think you are trying to make an entire docker container for every user. You don't strictly need that if you only plan to allow them to use your service as a simple IDLE.
You could use something like socat or xinetd to achieve the same.
Here is an example that uses socat to run a python script for anyone who connects to the server: https://gitlab.com/Milkdrop/xmas-2020/-/tree/master/misc/complaint
Also, I recommend AGAINST using exec() or eval() to allow others to execute code on your system. Actually, you should not use them in general either.

Automatically answer 'yes' on Python's 'click' prompts (unattended command run)

I have built a command line interface using Python's click library (version 7.1.2) that can run a command that asks the (human) user to answer certain confirmations on the way (The well known "Are you sure you want to continue? Y/n")
Now, I'm trying to run that command automatically on a Kubernetes CronJob and I need a way of "pretending" to input Y to each of the prompts.
I have seen the click.confirmation_option, but if I understand correctly, that seems more like a confirmation to run the whole command, right? (maybe I'm wrong?)
I'm more looking for something like some kind of assume_yes in the example below (could be passed either to the invocation or when creating full context ctx = cli.make_context...):
from my_command import cli
ctx = cli.make_context(
'main_command_group', ["action", "--num_times", 3]
)
with ctx:
result = cli.invoke(ctx, assume_yes=True)
Is that possible?
I can always add some kind of environment variable, or pass an extra boolean Option (a flag) to my Click command and edit my code so before even trying to show the confirmation prompt, it'd check whether the environment variable (or the flag) is True, and if so, then assume yes (without even showing the prompt), but it feels like Click must have something for unattended runs.
EDIT: (As per the comments)
The prompts look like:
customer = CustomerManager.get_by_name(customer_name)
if (
not customer and
click.confirm(f"Create customer {customer_name}", default=True)
):
customer = CustomerManger.create(name=customer_name)
# more code
if not customer.address:
if click.confirm(
f"No address for customer {customer.name}. Leave blank?",
default=True):
# ...
As to why doing it this way: Because the exact same code is going to be run first by humans (as a script... on the command line) and once the human user "ok"s it, it will be pushed to a pod where it'll be run by a CronJob.
Running the script on the command line will populate a local database, run some data checks, some verifications... So once everything is confirmed to be "good" locally by a human, a signal will be sent to a Kubernetes Cronjob that will do exactly the same as the humans. The only difference is that at that point it can assume the answer to all the prompts is "yes".
So yes: the code could be refactored, but it would be nice if it
didn't have to be (because when the CLI is run by the cronjob, we
already know that the answer to every confirmation prompt is going to
be a "yes")
How do you expect from Click_ to handle this out of the box? The system needs to know that you are a robot, and not a human. How could you achieve this? One way is to have some environment variable, another way is to use special API for your cron job. Nevertheless – you will end up with a special option for this case.
You are totally right – the confirmation_option doesn't cover your case, but it shows you how are you supposed to handle such cases.
So, what I would do is something like this:
#click.option('--yes', is_flag=True)
def my_method(customer_name, yes):
if not yes:
click.confirm(f"Create customer {customer_name}", default=False, abort=True)
customer = CustomerManger.create(name=customer_name)
You could use environment variables, but I don't see any reason to do it. You can force your cron job to provide the --yes option. It is easier and more obvious.
I played around with the abort=True here, because otherwise I need to repeat the create line one more time, but it may not be suitable for you, if you don't want to abort the whole command and just want to skip the creation of the customer.
And something not related to your question: I advise you to default to False (this is how Click_ works by default), instead of True in your confirmation. I could hit enter unintentionally and shoot myself in the foot. You won't have confirmation dialogue if it wasn't dangerous to confirm bad data, so better don't easy the confirmation that way :)
OK, if you want to do this globally, and not per command, you may override easily the confirm() behaviour:
def confirm(*args, **kwargs):
if not os.environ.get('yes'):
click.confirm(*args, **kwargs)
And than, you could use your local version of confirm, instead of click.confirm in your code:
#click.command()
def test():
confirm('Create customer', default=False, abort=True)
...
Now, if you export the yes environment variable, you will see the difference.

Input from Windows terminal for Python script

I am currently working on GT-suite (a multiphysics simulation software) and I want to be more efficient.
The software includes Python and an interface to write Python script and a console.
I would like to get an integer by the user, but when I use input(), I get the following error:
Traceback (most recent call back)
File «stdin» Line 29 in module
EOFError : EOF when reading a line
I searched a little and it seems that the console is only there for showing output and so I can’t input in it.
Is it possible to open a windows terminal when the function input() is read by Python, enter the integer in the windows terminal, press enter and then the integer input is read by the script?
I'm not familiar with the GT-suite, but if it's true the console is only used for output (and it sounds like that's the case), then you cannot used input() indeed.
Using subprocess to execute another script that uses input() will not work either, since the child process will not have access to the standard input if the parent process doesn't have it.
Some possible work-arounds I can think of are:
Look for an alternative way to get user input using the GT-suite software. If it supports such a thing, that would probably be the best and easiest solution. I searched for some information about it, but unfortunately couldn't find it. However, the website mentions a video in which "a script executes based on user inputs (...)", which suggests it should be possible (or I'm misunderstanding it). They also seem to have an API, but I couldn't acccess it without account. If you can find the API documentation, you might search for a way to get the user input.
You could create a simple GUI in Python, with a text input field for the number. That should work. However, this is not a simple/straightforward solution, and I doubt you will become "more efficient". But that depends on your use case and is for you to decide.
There are many GUI frameworks, but if you quickly want to test if entering numbers in the GUI will be possible, you could use the following code:
from tkinter import *
window = Tk()
txtfld = Entry(window, bd=5)
txtfld.place(x=0, y=0)
window.title('Enter number')
window.geometry("300x100")
window.mainloop()
This creates a small windows with a text field, where you could enter a number. It does not return the value to the main script yet. It's simply the bare minimum to test if such a solution would work in your situation. If this works, you could extend the script to your needs.

Examples of user-entered code that would cause an issue

Let's say the user has installed a python interpreter on their machine/browser, for example, using something like https://github.com/iodide-project/pyodide. I understand not allowing someone to enter in arbitrary code when they don't own the resources, for example doing something like:
exec('while 1: os.fork()')
However, if the user is executing the code on their own machine, is there anything wrong with allowing them to run arbitrary evals and execs, and just telling them "Please use at your own risk"? The use case is we give the user an environment to work with a spreadsheet, and they can enter in formulas using python, and we just 'pass-through' the entered string (in the spreadsheet cell) to their python environment.
If you are OK with the user being able to run arbitrary Javascript code client side (which is true for all websites), it should be also OK for them to run arbitrary code with Pyodide. Both are sandboxed by the browser.
For instance, they won't be able to interact with their actual file system, nor generally make any system calls that don't pass through the Webassembly VM. See https://webassembly.org/docs/security/ for more details.

Disable subprocess.Popen echo to command prompt window title in Python

I'm trying to use a Python's subprocess.Popen to build up a module for Python bindings to a command line interface; pretty much there as far as the CLI-bindings go, but I really want to be able to mask some "private" arguments.
The CLI uses account information, and I want to hide the account credentials from a command prompt title. Below is a screen capture of what appears when I use the login method for my CLI-bindings class.
I know that I'm using plain text for the password here ('TAIL') but I wanted to simply show the usage of what's going on. See from the image that the full command "sent" using the subprocess.Popen is displayed in the prompt's title.
I recently found that there is a way to programmatically change the title using either os or ctypes, so I could effectively mask, or cover-up, the "private" credentials I don't want shown on the command prompt title like shown here:
but is there a better way of disabling "echo-to-title" (for lack of a better name) with subprocess.Popen?
in fact passwords should never be passed as command line arguments to an executable.
Reason:
anybody being able to look at running processes and their parameters can see the password.
One solution is, that the parent process. puts the password in an environment variable and the program to be called fetches the parameter from an environment variable.
so the caller would be something like:
import os
os.environ["ACRTAC_PASSWORD"] = "TAIL"
subprocess.Popen([...])
and the acrtac.py
import os
password = os.environ["ACRTAC_PASSWORD"]

Categories

Resources