Can I call a function by inputting a string? - python

I want to make a function that can be called when the text input is equal to a command.
from os import system
from time import sleep
import ctypes
ctypes.windll.kernel32.SetConsoleTitleW('SimpleChat')
print('Hi, welcome to my basic chat engine!')
sleep(5)
system('cls')
username = input('Enter a username: ')
ctypes.windll.kernel32.SetConsoleTitleW('SimpleChat - ' + username)
system('cls')
def commands (command):
commandlist = ['/help','/clear', '/commands']
commanddict = {'/help' : 'help', '/clear' : 'clear', '/commands' : 'commands'}
for possibility in commandlist:
if command == possibilty:
commanddict[possibility]()
break
def textInput (text):
if text[0] == '/':
commands(text)
Does line 24 work to call a function? The way I am imagining it will work is that it will find the entry for the key 'possibility', and then call that as a function, but I am not sure.
If the previous code does not work, what would?

Suppose there's a function called help, clear,... in your code like this.
def help():
print("help!")
Then, the below commands function will do what you want.
Note that function can be used as value of dictionary in Python.
def commands (command):
command_dict = {'/help' : help, '/clear' : clear, '/commands' : commands}
func = command_dict.get(command)
if func is not None:
func()
else:
print("I don't have such a command: %s" % command)
I guess '/commands''s value(command function) in command_dict should be changed to another function. The program will crash if you type 'commands'.

Related

Using a delayed print function with input

I'm using this function to delay text:
def delay_print(s):
for c in s:
sys.stdout.write(c)
sys.stdout.flush()
time.sleep(0.05)
Here is my current start to my program:
name = input(delay_print('What is your name?\n'))
delay_print('Hi, %s.' % name,)
This results in this when used with my name
What is your name?
noneAndrew
Hi, Andrew.
How would I go about fixing this?
By calling the function inside the input() parameter section, you therefore let the input function prompt the user with the return value of delay_print (which is None, since it does not return anything). The way to fix this is to take it outside of the parameter section.
delay_print('What is your name?\n')
name = input()
delay_print('Hi, %s.' % name,)
Simply do not invoke the delay_print function inside the input function, like this:
delay_print('What is your name?\n')
name = input()
delay_print('Hi, %s.' % name,)
Which gives you:
What is your name?
Andrew
Hi, Andrew.
Try separating the input from the message:
import sys
import time
def delay_print(s):
for c in s:
sys.stdout.write(c)
sys.stdout.flush()
time.sleep(0.05)
delay_print('What is your name?')
name = input('\n')
delay_print('Hi, %s.' % name,)
If you are running with Python 3.8+, you can use the new assignment expression syntax that's supported in that version on and write the code like this:
import sys, time
def delay_print(s):
for c in s:
sys.stdout.write(c)
sys.stdout.flush()
time.sleep(0.05)
return s
delay_print('Hi, %s.' % (name := input('What is your name?\n')))

How do you store the click command line arguments/options for reference?

New to click here so I'm still learning. How do I store the click arguments/options in an object for later reference within my application? I thought of just creating an object and returning it from the setup function, but it doesn't seem to work. Here is what I did:
import click
import sys
class Cfg(object):
component = ""
command = ""
obj = ""
my_cfg = Cfg()
#click.command()
#click.argument('component')
#click.argument("command")
#click.argument("obj")
def set_args(component, command, obj):
cfg = Cfg()
if component != "optdata":
sys.stderr.write("Invalid option")
sys.exit(1)
else:
cfg.component = component
cfg.command = command
cfg.obj = obj
return cfg
if __name__ == "__main__":
app_cfg = Cfg()
app_cfg = set_args() # Never actually completes here.
print("Component = ", app_cfg.component, "Command = ", app_cfg.command, "Obj = ", app_cfg.obj)
There is some sort of exception raised in core.py which just does a sys.exit and doesn't raise any sort of actual error.
Your design goes against the idea of Click: You're not supposed to treat "parsing the options" and "doing the work" as two separate steps:
import click
#click.command()
#click.argument("component", type=click.Choice(["optdata"]))
#click.argument("command")
#click.argument("obj")
def cli(component, command, obj):
print("Component = ", component, "Command = ", command, "Obj = ", obj)
# put your business logic here
if __name__ == "__main__":
cli()
The pattern is to call the function that processes the command line options and then have that function call any other functionality.

How to set a prefix for all print() output in python?

I am printing to a console in python. I am looking for a one off piece of code so that all print statments after a line of code have 4 spaces at the start. Eg.
print('Computer: Hello world')
print.setStart(' ')
print('receiving...')
print('received!')
print.setStart('')
print('World: Hi!')
Output:
Computer: Hello world
receiving...
received!
World: Hi!
This would be helpful for tabbing all of the output that is contained in a function, and setting when functions output are tabbed. Is this possible?
You can define a print function which first prints your prefix, and then internally calls the built-in print function. You can even make your custom print() function to look at the call-stack and accordingly determine how many spaces to use as a prefix:
import builtins
import traceback
def print(*objs, **kwargs):
my_prefix = len(traceback.format_stack())*" "
builtins.print(my_prefix, *objs, **kwargs)
Test it out:
def func_f():
print("Printing from func_f")
func_g()
def func_g():
print ("Printing from func_g")
func_f()
Output:
Printing from func_f
Printing from func_g
Reverting back to the built-in print() function:
When you are done with your custom printing, and want to start using the built-in print() function, just use del to "delete" your own definition of print:
del print
Why not define your own custom function and use that when needed:
def tprint(*args):
print(' ', *args)
It would be used like so:
print('Computer: Hello world')
tprint('receiving...')
tprint('received!')
print('World: Hi!')
Output:
Computer: Hello world
receiving...
received!
World: Hi!
You might want to use specific prefixes only at specific places
import sys
from contextlib import contextmanager
#contextmanager
def add_prefix(prefix):
global is_new_line
orig_write = sys.stdout.write
is_new_line = True
def new_write(*args, **kwargs):
global is_new_line
if args[0] == "\n":
is_new_line = True
elif is_new_line:
orig_write("[" + str(prefix) + "]: ")
is_new_line = False
orig_write(*args, **kwargs)
sys.stdout.write = new_write
yield
sys.stdout.write = orig_write
with add_prefix("Computer 1"):
print("Do something", "cool")
print("Do more stuffs")
with add_prefix("Computer 2"):
print("Do further stuffs")
print("Done")
#[Computer 1]: Do something cool
#[Computer 1]: Do more stuffs
#[Computer 2]: Do further stuffs
#Done
The advantage is that it's a utility function, i.e. you just have to import to use it, without having to redefine every time you write a new script.

Simple Python program with arguments not working

Just learning Python and spent quite some time on this. Why isn't it outputting anything when I pass arguments like this:
python new2.py Alice
Source code:
#!/usr/bin/python
import sys
def Hello(name):
if name == 'Alice' or name == 'Nick':
name = name + '!!!'
else:
name = name + '???'
print 'Hello', name
def main():
Hello(sys.argv[1])
Python doesn't implicitly call your main function. You either call it directly:
def main():
Hello(sys.argv[1])
main()
or you wrap it in an idiomatic clause to do a similar thing:
if __name__ == "__main__":
main()

Detect and print if no command line argument is provided

This is the program I have:
from sys import argv
script, arg1 = argv
def program(usr_input, arg1):
if(usr_input == arg1):
print "CLI argument and user input are identical"
else:
print "CLI argument and user input aren't identical"
if arg1 != "":
usr_input = raw_input("enter something: ")
program(usr_input, arg1)
else:
print "You have not entered a CLI argument at all."
I get:
Traceback (most recent call last):
File "filename.py", line 3, in <module>
script, arg1 = argv
ValueError: need more than 1 value to unpack
How can I detect the lack of command line argument and throw an error/exception instead of receiving this error?
I would recommend just checking the program args in the __main__ location of your script, as an entry point to the entire application.
import sys
import os
def program(*args):
# do whatever
pass
if __name__ == "__main__":
try:
arg1 = sys.argv[1]
except IndexError:
print "Usage: " + os.path.basename(__file__) + " <arg1>"
sys.exit(1)
# start the program
program(arg1)
You can handle the exception:
In [6]: def program(argv):
try:
script, argv1 = argv
except ValueError:
print("value error handled")
...:
In [7]: program(argv)
value error handled
try this:
script = argv[0]
try:
arg1 = argv[1]
except:
arg1 = ''
You could use a try statement there:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import sys
class MyError(Exception):
def __init__(self, value):
self.error_string = value
def __str__(self):
return eval(repr(self.error_string))
try:
script, arg1 = sys.argv
except ValueError:
raise MyError, "Not enough arguments"
Seeing that sys.argv is a list you should check the length of the list to make sure it is what you wish it to be. Your script with minor changes to check the length:
from sys import argv
def program(usr_input, arg1):
if(usr_input == arg1):
print "CLI argument and user input are identical"
else:
print "CLI argument and user input aren't identical"
if len(argv)== 2:
arg1 = argv[1]
usr_input = raw_input("enter something: ")
program(usr_input, arg1)
else:
print "You have not entered a CLI argument at all."

Categories