Recently i saw a post about someone making a program that could control a computer it was launched on. (it was this one) Add commands to user input
I was really interested in it and I wanted to replicate it and improve my python skills on the way.
After watching some tutorials I had the ability to send and recieve emails and started working on some commands. First I added the ability to take screenshots as its the most important one. I then added functions and commands to do other stuff. Then I wanted to add a help command to display all commands if there is no args and the description of a specific command if there is an args. I first added the one without args and this is the code for it:
import json
user_input = "$say hello\n$help"
def help(*args):
if args == ():
for func_name, aliases in info_json.items():
print(func_name)
else:
pass
#print the description for the command
def command1():
print("I am command 1.")
def command2():
print("I am command 2.")
def command3():
print("I am command 3.")
def say(*args):
print(f"You said i should say \"{' '.join(args)}\"! Very cool :D")
def pause(sec):
print(f"I waited for {sec} seconds!")
commands = {
"$help":help,
"$pause":pause,
"$say":say,
"$command1":command1,
"$command2":command2,
"$command3":command3,
}
with open("commands.json") as json_file:
help_json = json.load(json_file)
def call_command(BEFEHL):
function, *args = BEFEHL.split(' ')
commands[function](*args)
for line in user_input.split("\n"):
try:
call_command(line)
except KeyError:
print("This command does not exist.")
I replaced the actual functions with print statements like the original author did :D
This code worked very well and I started to work on the description on specific functions. I created the commands.json example:
{
"command1": ["This command is command 1. It prints out 'I am command 1' "],
"command2": ["This command is command 2. It prints out 'I am command 2' "],
"command3": ["This command is command 3. It prints out 'I am command 3' "]
}
Is there any way you can print out the stuff in the json which stands behind the command? An example use would be:
>>> $help command1
print("This is command 1. It prints out 'I am command 1' ")
I would really appreciate to know if this is possible! :D
When you load a json, it basically acts like a Python dictionary, so you can retrieve the description of the command from its key, which you are passing as parameter.
Your help() function should look something like this:
def help(*args):
if args == ():
for func_name, aliases in help_json.items():
print(func_name)
else:
print(help_json.get(args[0], "Command does not exist"))
The second argument "Command does not exist" is the default value to print when the get() cannot find the key in the dictionary.
Related
I started building a bot with the Telethon library but couldn't find a clean way to separate the command from the text.
For example, with the python-telegram-bot library, I can retrieve the first argument after the command like this:
def test(update, context):
arg_1 = context.args[0]
print(arg_1) # Prints the first word after the command
So... There's a way to make something like this using Telethon? (I'm using this piece of code to split text from command but I think this method is not really good):
txt = event.message.message.lower()
try:
txt.split("!raw ")[1]
text = event.message.message[4:]
except Exception as e:
text = ""
if text:
do_something()
If you have a handler defined in the following way:
#client.on(events.NewMessage(pattern=r'!raw (\w+)'))
async def handler(event):
...
You can then access the event.pattern_match:
arg = event.pattern_match.group(1)
print(arg) # first word
However, using .split() is also okay:
parts = event.raw_text.split()
if len(parts) > 1:
arg = parts[1]
(And you can also build a better UX, by telling the user when they used the command wrong.)
I'm trying to make a custom command line to control a robotic arm.
So I want to be able to run the program and type in servoMove(arg1,arg2) and have arg1 and arg2 get transferred into the function servoMove.
servoPos = [0,1,2,3,4]
def servoMove(servo,angle):
servoPos[servo] = angle
print(servoPos[servo])
def commands(cmd):
if cmd == 'servoMove('+arg1+','+arg2+')':
servoMove(arg1,arg2)
else:
print("[Error] - Unknown Command")
commands(input(""))
Clearly, the code below doesn't work for this.
if cmd == 'servoMove('+arg1+','+arg2+')':
servoMove(arg1,arg2)
Does anybody know how I can do this?
You can use a regular expression to parse the command.
import re
def commands(cmd):
m = re.match(r'servoMove\((\d+),(\d+)\)', cmd)
if m:
servoMove(int(m.group(1)), int(m.group(2)))
return
# Put similar tests for other commands here
# ...
print("[Error] - Unknown Command")
This is a really crude way to do it -- if the user doesn't enter the command exactly right it will complain that the command is unknown. If you want something more robust, you need to learn how to write a real parser. Or use a better user interface, such as Tkinter to implement a form that the user can fill out.
You can use the cmd module to build a command line interface.
Here's an example:
import cmd
servoPos = [0,1,2,3,4]
def servoMove(servo,angle):
servoPos[servo] = angle
print(servoPos[servo])
class ServoShell(cmd.Cmd):
prompt = '=> '
def do_servoMove(self, arg):
'Edit this to give a description to the function when typing ?'
servoMove(*parse(arg))
def parse(arg):
'Convert a comma separated string into a tuple'
return tuple(map(int, arg.strip('()').split(',')))
if __name__ == '__main__':
ServoShell().cmdloop()
Just looking at the structure the problem is in the if statement: arg1 and arg2 are undefined at that stage, so you'll get a False. For starters you'd want to replace that with something like:
#Look at the nine first characters to see if they match your function
if cmd[:9] == 'servoMove':
To extract your arguments, I'd use some string manipulation as in here. I've sliced the input to take the text between "(" and "," as arg1, and "," and ")" as arg2.
arg1 = cmd[cmd.find("(")+1:cmd.find(",")]
arg2 = cmd[cmd.find(",")+1:cmd.find(")")]
Putting it together:
def commands(cmd):
if cmd[:9] == 'servoMove':
arg1 = cmd[cmd.find("(")+1:cmd.find(",")]
arg2 = cmd[cmd.find(",")+1:cmd.find(")")]
servoMove(arg1, arg2)
else:
print("[Error] - Unknown Command")
Ok so here is part of my code (I have imported sys)
if __name__ == '__main__':
MyCaesarCipher = CaesarCipher() #MyCaesarCipher IS a CaesarCipher()
if len(sys.argv) >1:
#what will it check?
Done = False
while not Done:
print('C Clear All')
print('L Load Encrypted File')
print('R Read Decrypted File')
print('S Store Encrypted File')
print('W Write Decrypted File')
print('O Output Encrypted Text')
print('P Print Decrypted Text')
print('E Encrypt Decrypted Text')
print('D Decrypted Encrypted Text')
print('Q Quit')
print('----------------')
print('Enter Choice>')
So the thing is I want to do is if the command line length is more than 1, the program runs as a script.
This is the instruction:
If no command line arguments are input, then the script enters menu
mode. If more than 1 command line argument (anything other than script
name) is provided during the run of the script it enters single run
mode.
I do not know what this means, though.
What is sys.arvg:
The list of command line arguments passed to a Python script. argv[0] is the script name.
Demo:
File Name: 1.py
import sys
if __name__=="__main__":
print "command arguments:", sys.argv
Output:
$ python 1.py arg1 arg2
command arguments: ['1.py', 'arg1', 'arg2']
$ python 1.py
command arguments: ['1.py']
Your problem is, we have to run code by Command Line Argument and by Menu also.
When User provided the Enter Choice from the command line then use provided value to next process.
If User not provided the Enter Choice from the command line then ask User to Enter Choice from the Menu.
Demo:
File Name: 1.py
import sys
if __name__ == '__main__':
try:
arg_command = sys.argv[1]
except IndexError:
arg_command = ""
Done = False
while not Done:
if arg_command=="":
print('\nMenu')
print('C Clear All')
print('L Load Encrypted File')
print('Q Quit')
print('----------------')
print('Enter Choice>')
command = raw_input('Enter Selection> ').strip()[0].upper()
else:
command = arg_command
#- set arg value to empty to run Menu option again.
arg_command = ""
if command == 'C':
print "In Clear All event."
elif command == 'L':
print "In Clear All event."
elif command == "Q":
break
else:
print "Wrong Selection."
Output:
Enter Choice given from the Command Line:
$ python 1.py C
In Clear All event.
Menu
C Clear All
L Load Encrypted File
Q Quit
----------------
Enter Choice>
Enter Selection> q
$
No Command Line argument.
$ python 1.py
Menu
C Clear All
L Load Encrypted File
Q Quit
----------------
Enter Choice>
Enter Selection> l
In Clear All event.
Menu
C Clear All
L Load Encrypted File
Q Quit
----------------
Enter Choice>
Enter Selection> q
$
Here's the thing, when you're learning a language like this, you can often get by pretty well with just printing out things you don't really understand.
Try this:
Step 1) Make a program that looks like this:
import sys
if __name__ == '__main__':
for idx, arg in enumerate(sys.argv):
print("arg #{} is {}".format(idx, arg))
print len(sys.argv)
After that, run your program from the command line like this:
$ python3 test_script.py
Then, run it like this:
$ python3 test_script.py somearg someother andanother etc "23908452359"
What you discover may be useful to perform this task you are looking to resolve.
Lastly, "menu mode" sounds like the script is going to take input from the user. Thus, you'll need to use input() to do that. It also sounds like you need to come to some decision about when to use menu mode or not, which you've already started to do with your if-test above.
Experiment a bit, though, and you'll figure it out.
The instructions want the script to use the command line arguments to execute the script.
python script.py [arg1] [arg2] [arg3] ....
The args are accessible through sys.argv.
sys.argv = ['script.py', '[arg1]', '[arg2]', '[arg3]']
You will need to use a command line interface instead of the menu interface when args are present.
Since you seem to be pretty new to python here's a simple example using your code. You'll have to complete the menu and the actual code for the menu options but it does use sys.argv
import sys
def menu():
Done = False
while not Done:
print('C Clear All')
print('L Load Encrypted File')
print('R Read Decrypted File')
print('S Store Encrypted File')
print('W Write Decrypted File')
print('O Output Encrypted Text')
print('P Print Decrypted Text')
print('E Encrypt Decrypted Text')
print('D Decrypted Encrypted Text')
print('Q Quit')
print('----------------')
print('Enter Choice>') #should get user input here
Done = True
if __name__=="__main__" :
if len(sys.argv) > 1 :
#Here if an argument is present run it or load the menu
print "run whatever option was entered on the commandline"
else:
menu()
First of all you have to understand what argv is, try creating this script, and call it learning_argv.py
import sys
print(sys.argv)
now try running the script like this:
$ python3 learning_argv.py
$ python3 learning_argv.py a
$ python3 learning_argv.py a b c
$ python3 learning_argv.py AWESOME TEXT
See what argv is?
What you're doing when you test if the length of argv is bigger than one, is basically testing if you're receiving anything beyond the script name.
In the future, you could create a similar structure you created for your menu, to treat arguments sent directly from the command line.
take a look at this quick tutorial in order to better understand argv.
Essentially, i want what is in this thread: Output to console while preserving user input in ruby, but in Python. I have googled for quite a while, and found an ALMOST working solution, except that it blocked the main thread, as long as i wasn't typing anything in and pressing enter.
Some output of what i don't want to happen is here:
/raw:jtv!jtv#jtv.tmi.twitch.tv PRIVMSG #cobaltstreak :USERCOLOR ullr_son_of_sif #DAA520
Some example input of what i want is:
:jtv!jtv#jtv.tmi.twitch.tv PRIVMSG #cobaltstreak :USERCOLOR ullr_son_of_sif #DAA520
/raw
PRIV:jtv!jtv#jtv.tmi.twitch.tv PRIVMSG #cobaltstreak :SPECIALUSER nightbot subscriber
MSG #cobaltstreak :This shouldn't be here, but on the same line with /raw
This meaning, i want the bottom line of the console to preserve input, while outputting everything happening in the main thread without affecting input.
My current code is:
def console(q, m, lock):
while 1:
raw_input() # After pressing Enter you'll be in "input mode"
with lock:
i = raw_input('> ')
cmd = i.split(' ')[0]
msg = i.strip(cmd + ' ')
q.put(cmd)
m.put(msg)
if cmd == 'quit':
break
as well has:
cmd = cmd_queue.get()
msg = msg_queue.get()
action = cmd_actions.get(cmd)
if action is not None:
action(stdout_lock, msg)
Note the code above is the very first couple of lines in my while loop.
I am on Windows and using python 2.7.6
I was asked to simulate CLI with Python.
This is what I did
def somefunction(a,b):
//codes here
//consider some other functions too
print "--- StackOverFlow Shell ---"
while True:
user_input = raw_input("#> ")
splitit = user_input.split(" ")
if splitit[0] == "add":
firstNum = splitit[1]
sNum = splitit[2]
result = somefunction(firstNum, sNum)
print result
//consider some other elif blocks with "sub", "div", etc
else:
print "Invalid Command"
I do also check the length of the list, here "splitit" I will allow only 3 argumets, first will be the operation, and second and third are the arguments with which some functions are to be performed, in case the argument is more than 3, for that i do put a check.
Though Somehow I manage to make it work, but is there a better way to achieve the same?
Use python CMD Module:
Check few examples given on the below pages
http://docs.python.org/library/cmd.html # Support for line-oriented command interpreters
http://www.doughellmann.com/PyMOTW/cmd - # Create line-oriented command processors
prompt can be set to a string to be printed each time the user is asked for a new command.
intro is the “welcome” message printed at the start of the program.
eg:
import cmd
class HelloWorld(cmd.Cmd):
"""Simple command processor example."""
prompt = 'prompt: '
intro = "Simple command processor example."
You should check out the VTE lib:
http://earobinson.wordpress.com/2007/09/10/python-vteterminal-example/
It works really well and you can very easily customize its look. This is how easy it is:
# make terminal
terminal = vte.Terminal()
terminal.connect ("child-exited", lambda term: gtk.main_quit())
terminal.fork_command()
# put the terminal in a scrollable window
terminal_window = gtk.ScrolledWindow()
terminal_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
terminal_window.add(terminal)