So I'm trying to make a CLI but I'm having some errors with the 'cd' command. I can't access the 'target_path' variable from my cd command. Here's the code for the CLI:
import os, colorama
ERROR_COLOR = colorama.Back.RED + colorama.Fore.BLACK
user = os.getlogin()
target_path = f'C:\\Users\\{user}'
class Commands:
def __init__(self):
raise RuntimeError("Cannot instantiate class 'Commands'")
#staticmethod
def help(cmd=None):
cmd_help_msgs = {
'help': \
"""
HELP:
USAGE:
help [command: str]
DESCRIPTION:
Prints out the description and usage of a command.
If command is not passed, it prints out the help messages of all commands
""",
'cls': \
"""
CLS:
USAGE:
cls
DESCRIPTION:
Clears the terminal
""",
'exit': \
"""
EXIT:
USAGE:
exit
DESCRITPION:
Quits the program
""",
'echo': \
"""
ECHO:
USAGE:
echo <msg: str>
DESCRIPTION:
Prints out msg
"""
}
help_msg = f"""
IMPORTANT: [] = optional parameter, <> = mandatory parameter
COMMANDS:
"""
if cmd is None:
print(help_msg, end='')
for val in cmd_help_msgs.values():
print(val, end='')
else:
try:
print(help_msg, end='')
print(cmd_help_msgs[cmd])
except:
print(f"{ERROR_COLOR}'{cmd}' is not recognized as a valid command! Do 'help' to see all valid commands{colorama.Style.RESET_ALL}")
return
print('\n')
#staticmethod
def cls():
os.system('cls')
#staticmethod
def exit():
exit(0)
#staticmethod
def echo(msg=''):
if msg == '':
print(ERROR_COLOR + "Missing required argument 'msg'" + colorama.Style.RESET_ALL)
return
print(msg)
#staticmethod
def cd(directory=''):
if directory == '':
print(target_path)
return
if directory[1] != ':':
if os.path.exists(target_path + directory) and os.path.isdir(target_path + directory):
target_path += directory
else:
print(f"{directory} is not a valid directory")
else:
if os.path.exists(directory) and os.path.isdir(directory):
target_path = directory
else:
print(f"{directory} is not a valid directory")
command_list = [func for func in dir(Commands) if callable(getattr(Commands, func)) and not func.startswith('__')]
os.system('cls')
while True:
command_has_kws = False
command = input(f'[{target_path}]{colorama.Fore.CYAN} # {colorama.Fore.LIGHTBLUE_EX}').strip().split(' ')
print(colorama.Style.RESET_ALL, end='')
for i in range(len(command)):
command[i] = command[i].strip()
if command[i].startswith('-'):
command_has_kws = True
if command[0] in command_list:
try:
if not command_has_kws:
getattr(Commands, command[0])(*command[1:])
else:
# REMINDER: Type 'getattr(Commands, command[0]).__code__.co_varnames[:getattr(Commands, command[0]).__code__.co_argcount]' to get the parameters of a command
pass # TODO: Implement keywords
except TypeError:
print(f"{ERROR_COLOR}Too many or too little arguments were passed to '{command[0]}'{colorama.Style.RESET_ALL}")
else:
print(f"{ERROR_COLOR}'{command[0]}' is not recognized as a valid command! Do 'help' to see all valid commands{colorama.Style.RESET_ALL}\n")
Here's 2 things you should focus on:
target_path = f'C:\\Users\\{user}'
And:
#staticmethod
def cd(directory=''):
if directory == '':
print(target_path)
return
if directory[1] != ':':
if os.path.exists(target_path + directory) and os.path.isdir(target_path + directory):
target_path += directory
else:
print(f"{directory} is not a valid directory")
else:
if os.path.exists(directory) and os.path.isdir(directory):
target_path = directory
else:
print(f"{directory} is not a valid directory")
Also here's the error message:
Traceback (most recent call last):
File "C:\Users\[REDACTED]\Desktop\Crabby_CLI\main.py", line 132, in <module>
getattr(Commands, command[0])(*command[1:])
File "C:\Users\[REDACTED]\Desktop\Crabby_CLI\main.py", line 102, in cd
if os.path.exists(target_path + directory) and os.path.isdir(target_path + directory):
UnboundLocalError: local variable 'target_path' referenced before assignment
INFORMATION:
Interpreter - Python 3.8
OS - Windows 10
Editor - PyCharm Community Edition
local variable 'target_path' referenced before assignment this error suggests that you are trying to access target_path in one of your functions before assigning any value and if my understanding is correct, you want to use the global target_path, that you have set in top, within those functions.
If this is correct, then you need to tell your functions to use global variables.
Solution :
Within each function that uses the 'target_path' variable, in the beginning, put this line
def abc():
# add this line
global target_path
...
...
# now use `target_path` here
Related
I have already written a simple python cmd program using the cmd module. However, I would like it to be modular. For Example, there would be a folder named script and any .py that contains a command would add the command to the application. How would I go about that?
NOTE:
I have figured out how to find and load modules that are within a folder using importlib.
First, you must understand how the cmd module works. I would not go into it here but the gist is command is entered, then split up into the actual command itself and its arguments. The command is then searched in the implementation of the cmd module using getattr(). The resulting function returned is then executed. Raises an error if the function(attribute) is not found.
Add the list of modules added to a list.
lst.append(importlib.importlib.import_module(<module path here>))
When cmd is finding a command, modify the code to get it to run through the list of imported modules and see if the function/command exists in that module. If so, execute it.
rough code to find func
def findfunc(funcname):
for module in lst:
if hasattr(<module class where func is stored>, "<funcname>"):
return getattr(<module class where func is stored>,"<funcname>")
However, I will leave my implementation here. It also includes the capability to reload modules(limited to a certain extent) and private commands that do not show up in help or autocomplete(I am using py prompt toolkit). A fair bit of warning, no docs or help in understanding this code as it is only meant for my personal use only. Meaning don't directly copy it and also It was a modification to the python cmd module.
import importlib
import os
import string
import sys
import time
from prompt_toolkit import PromptSession
from prompt_toolkit.completion import WordCompleter
from prompt_toolkit.styles import Style
from internal.logger import logger # my logger Implementation, ignore it
__all__ = ["cli2"]
PROMPT = '>>> '
IDENTCHARS = string.ascii_letters + string.digits + '_'
style = Style.from_dict(
{
"completion-menu.completion": "bg:#008888 #ffffff",
"completion-menu.completion.current": "bg:#00aaaa #000000",
"scrollbar.background": "bg:#88aaaa",
"scrollbar.button": "bg:#222222",
}
)
def parse(arg):
return arg.split()
class Interpreter:
identchars = IDENTCHARS
ruler = '='
lastcmd = ''
doc_leader = ""
doc_header = "Available Commands (type help <topic> to get documentation for <topic> ):"
misc_header = "Miscellaneous help topics:"
nohelp = "*** No help on %s"
use_rawinput = 1
modulelst = []
internalcmdlst = ["help", "exit", "reload", "listmodules", "listvar"]
def __init__(self, intro=None, prompt=PROMPT, stdin=None, stdout=None):
"""Instantiate a line-oriented interpreter framework.
The optional arguments stdin and stdout
specify alternate input and output file objects; if not specified,
sys.stdin and sys.stdout are used.
"""
self.prompt = prompt
self.intro = intro
if stdin is not None:
self.stdin = stdin
else:
self.stdin = sys.stdin
if stdout is not None:
self.stdout = stdout
else:
self.stdout = sys.stdout
self.cmdqueue = []
def cmdloop(self):
self.preloop()
try:
if self.intro:
self.stdout.write(str(self.intro) + "\n")
stop = None
while not stop:
if self.cmdqueue:
line = self.cmdqueue.pop(0)
else:
line = self.session.prompt(self.prompt)
line = self.precmd(line)
stop = self.onecmd(line)
stop = self.postcmd(stop, line)
self.postloop()
finally:
pass
def precmd(self, line):
"""Hook method executed just before the command line is
interpreted, but after the input prompt is generated and issued.
"""
# Parse command to argument
return self.parseline(line)
def postcmd(self, stop, line):
"""Hook method executed just after a command dispatch is finished."""
return stop
def preloop(self):
"""Hook method executed once when the cmdloop() method is called."""
self.autocommands = [item[3:] for item in self.get_names() if (item[-5:] != '__pvt') and (item[:3] == 'do_')]
self.session = PromptSession(completer=WordCompleter(self.autocommands, ignore_case=False))
def postloop(self):
"""Hook method executed once when the cmdloop() method is about to
return.
"""
self.autocommands, self.session = None, None
def parseline(self, line):
"""Parse the line into a command name and a string containing
the arguments. Returns a tuple containing (command, args, line).
'command' and 'args' may be None if the line couldn't be parsed.
"""
line = line.strip()
if not line:
return None, None, line
elif line[0] == '?':
line = 'help ' + line[1:]
elif line[0] == '!':
if hasattr(self, 'do_shell'):
line = 'shell ' + line[1:]
else:
return None, None, line
i, n = 0, len(line)
while i < n and line[i] in self.identchars: i = i + 1
cmd, arg = line[:i], line[i:].strip()
return cmd, arg, line
def onecmd(self, linecommand):
"""Interpret the argument as though it had been typed in response
to the prompt.
This may be overridden, but should not normally need to be;
see the precmd() and postcmd() methods for useful execution hooks.
The return value is a flag indicating whether interpretation of
commands by the interpreter should stop.
"""
cmd, arg, line = linecommand
if not line:
return self.emptyline()
if cmd is None:
return self.default(line)
self.lastcmd = line
if line == 'EOF':
self.lastcmd = ''
if cmd == '':
return self.default(line)
if cmd in self.internalcmdlst:
return self.getfunc(cmd)(arg)
else:
try:
terminalclass, func = self.getfunc(cmd)
except AttributeError:
return self.default(line)
return func(terminalclass, arg)
def emptyline(self):
"""Called when an empty line is entered in response to the prompt.
If this method is not overridden, it repeats the last nonempty
command entered.
"""
if self.lastcmd:
return self.onecmd(self.lastcmd)
def default(self, line):
"""Called on an input line when the command prefix is not recognized.
If this method is not overridden, it prints an error message and
returns.
"""
self.stdout.write('*** Unknown syntax: %s\n' % line.split(" ")[0])
def get_names(self):
# This method used to pull in base class attributes
# at a time dir() didn't do it yet.
lst = [*dir(self.__class__)]
for modulejs in self.modulelst:
terminalclass = getattr(getattr(modulejs["module"], 'cli_helper'), "Terminal")
lst += dir(terminalclass)
return lst
def print_topics(self, header, cmds, maxcol):
if cmds:
self.stdout.write("%s\n" % str(header))
if self.ruler:
self.stdout.write("%s\n" % str(self.ruler * len(header)))
self.columnize(cmds, maxcol - 1)
self.stdout.write("\n")
def columnize(self, lst, displaywidth=80):
"""Display a list of strings as a compact set of columns.
Each column is only as wide as necessary.
Columns are separated by two spaces (one was not legible enough).
"""
if not lst:
self.stdout.write("<empty>\n")
return
nonstrings = [i for i in range(len(lst))
if not isinstance(lst[i], str)]
if nonstrings:
raise TypeError("list[i] not a string for i in %s"
% ", ".join(map(str, nonstrings)))
size = len(lst)
if size == 1:
self.stdout.write('%s\n' % str(lst[0]))
return
# Try every row count from 1 upwards
for nrows in range(1, len(lst)):
ncols = (size + nrows - 1) // nrows
colwidths = []
totwidth = -2
for col in range(ncols):
colwidth = 0
for row in range(nrows):
i = row + nrows * col
if i >= size:
break
x = lst[i]
colwidth = max(colwidth, len(x))
colwidths.append(colwidth)
totwidth += colwidth + 2
if totwidth > displaywidth:
break
if totwidth <= displaywidth:
break
else:
nrows = len(lst)
ncols = 1
colwidths = [0]
for row in range(nrows):
texts = []
for col in range(ncols):
i = row + nrows * col
if i >= size:
x = ""
else:
x = lst[i]
texts.append(x)
while texts and not texts[-1]:
del texts[-1]
for col in range(len(texts)):
texts[col] = texts[col].ljust(colwidths[col])
self.stdout.write("%s\n" % str(" ".join(texts)))
def addmodulesfromdirectory(self, directory):
try:
directory_contents = os.listdir(directory)
for item in directory_contents:
self.addmodule(os.path.join(directory, item), "".join([directory[2:], ".", item]))
except OSError as e:
print("Something Happened\nPlease try again :)")
logger.error("OSErrot, {}".format(e))
except ImportError as e:
print("Something Went Wrong while importing modules\nPlease try again :)")
logger.error("ImportError, {}".format(e))
except Exception as e:
print("Oops, my fault\nPlease try again :)")
logger.error("Exception, {}".format(e))
finally:
logger.info("Done importing cli modules")
def addmodule(self, pathdir, importdir):
if os.path.isdir(pathdir):
importedmodule = importlib.import_module(importdir)
modulejs = {
"module": importedmodule,
"name": importedmodule.__name__,
"importdir": importdir,
"pathdir": pathdir
}
self.modulelst.append(modulejs)
def removemodule(self, modulename):
if modulename in [x["name"] for x in self.modulelst]:
self.modulelst.remove(self.getmodulejs(modulename))
del sys.modules[modulename]
else:
raise ModuleNotFoundError
def replacemodule(self, modulename):
module = self.getmodulejs(modulename)
self.removemodule(modulename)
self.addmodule(module["pathdir"], module["importdir"])
def getmodulejs(self, modulename):
for i in self.modulelst:
if i['name'] == modulename:
return i
#staticmethod
def getmoduledep(modulename):
unsortedscriptsysmodules = [module for module in sys.modules if (("script" in module) and ("script" != module))]
sortedlst = []
for scriptmodules in unsortedscriptsysmodules:
mod = sys.modules[scriptmodules]
if not (hasattr(mod, "__path__") and getattr(mod, '__file__', None) is None) and (
scriptmodules != "script.{}".format(modulename)):
sortedlst.append(sys.modules[scriptmodules])
return sortedlst
def reloadmoduledep(self, modulename):
for dep in self.getmoduledep(modulename):
try:
importlib.reload(dep)
except ModuleNotFoundError as e:
print(e)
def getfunc(self, command):
if "do_" in command:
command = command[3:]
if command in self.internalcmdlst:
return getattr(self, "_".join(['do', command]))
else:
for modulejs in self.modulelst:
terminalclass = getattr(getattr(modulejs["module"], 'cli_helper'), "Terminal")
if hasattr(terminalclass, "_".join(['do', command])):
return terminalclass, getattr(terminalclass, "_".join(['do', command]))
raise AttributeError
def do_help(self, arg):
"""
List available commands with "help" or detailed help with "help cmd".
"""
if arg:
# XXX check arg syntax
try:
func = self.getfunc('help_' + arg)
except AttributeError:
try:
if arg[-5:] == '__pvt':
raise AttributeError
doc = self.getfunc('do_' + arg).__doc__
if doc:
self.stdout.write("%s\n" % str(doc))
return
except AttributeError:
pass
self.stdout.write("%s\n" % str(self.nohelp % (arg,)))
return
func()
else:
names = self.get_names()
cmds_doc = []
funchelp = {}
for name in names:
if name[:5] == 'help_':
funchelp[name[5:]] = 1
names.sort()
# There can be duplicates if routines overridden
prevname = ''
for name in names:
if name[:3] == 'do_' and name[-5:] != '__pvt':
if name == prevname:
continue
prevname = name
cmd = name[3:]
if cmd in funchelp:
cmds_doc.append(cmd)
del funchelp[cmd]
elif self.getfunc(name).__doc__:
cmds_doc.append(cmd)
self.stdout.write("%s\n" % str(self.doc_leader))
self.print_topics(self.doc_header, cmds_doc, 80)
self.print_topics(self.misc_header, list(funchelp.keys()), 80)
def do_exit(self, arg):
"""
Exit
"""
if arg:
print(self.prompt + "No arguments please")
print("Exiting")
time.sleep(1)
return True
def do_reload(self, arg):
if arg == "":
print("No Arguments found")
return
arg = parse(arg)
if arg[0] == "all":
localmodulelst = self.modulelst.copy()
self.modulelst = []
for i in localmodulelst:
print("Reloading", ".".join(i["name"].split(".")[1:]))
importlib.invalidate_caches()
self.reloadmoduledep(i["name"])
self.addmodule(i["pathdir"], i["importdir"])
self.autocommands = [item[3:] for item in self.get_names() if
(item[-5:] != '__pvt') and (item[:3] == 'do_')]
self.session = PromptSession(completer=WordCompleter(self.autocommands, ignore_case=False))
else:
print("Only argument \'all\' is accepted")
def do_listmodules(self, arg):
arg = parse(arg)
if arg[0] == "sys":
for i in sys.modules:
print(i)
elif len(arg) != 0:
print("No Argument Please")
else:
print("Listing all imported Modules")
for i in self.modulelst:
print(".".join(i["module"].__name__.split(".")[1:]))
I created a class and function. the function is creating a new object and executing other operations and returns the object.
class DoublyLinkedList:
def __init__(self, element):
self.item = element
self.before = None
self.after = None
def __str__(self):
if self.before is None:
return f'Previous node : {None}, item : {self.item}, Next node : {self.after.item};'
elif self.after is None:
return f'Previous node : {self.before.item}, item : {self.item}, Next node : {None};'
else:
return f'Previous node : {self.before.item}, item : {self.item}, Next node : {self.after.item};'
def addToHeadDLL(element, head):
try:
name = DoublyLinkedList(element)
except NameError:
print('Please enter correct parameters')
else:
head.before = name
name.after = head
print('List added to Head')
return name
a = DoublyLinkedList(1)
b = DoublyLinkedList(2)
a.after = b
b.before = a
c = addToHeadDLL(3, a) #Works
d = addToHeadDLL(4, e) #Produces NameError
When NameError occurs it has to print "Please enter correct parameters". But the output is like this,
List added to Head
Traceback (most recent call last):
File "c:/Users/JBallipalli/Desktop/Codes/dll.py", line 43, in <module>
d = addToHeadDLL(4, e)
NameError: name 'e' is not defined
Please help me solve this...
EDIT:
It's not that try-except- else not run in function. Check the following code. it does run.
import os
def openfolder(dir):
"""Opens folder in file explorer
Args:
dir (str): path of the folder
"""
os.startfile(dir)
def access(dir):
"""Checking access to the given directory
Args:
dir (str): directory path
Returns:
bool, list: status, list of files & folders in the directory path
"""
try:
filesList = os.listdir(dir)
except PermissionError:
print(f'No permission to access {os.path.basename(dir)}')
print(f'Please delete the file in {os.path.basename(dir)} manually')
folder = input('Do you wanna open folder in file explorer? type y/n : ')
if folder[0].lower() == 'y':
openfolder(dir)
return False, None
else:
return True, filesList
path = r'C:\Users\JBallipalli\Recent' # raises PermissionError
permission, files = access(path)
and check the output:
No permission to access Recent
Please delete the file in Recent manually
Do you wanna open folder in file explorer? type y/n :
The only difference between these two functions is above (DoublyLinkedList) code calls class inside a function and other doesn't. I want to know why its behaviour like that?
my Python version : 3.7.6
NameError is returned when you're calling function, as python doesn't know what to pass as e.
It never gets to the exception handling part in addToHeadDLL.
Do not use try and except in function,
If You want NameError then call function addToHeadDLL in try block.
Like that
try:
d = addToHeadDLL(4, e) #Produces NameError
except:
print("Name error")
To add to what everyone have said, you could modify you code like the sample below to fit your use case...
This time, you handle the error at function level...
def addToHeadDLL(element, head):
name = DoublyLinkedList(element)
if not isinstance(head, type(name)):
raise NameError('Please enter correct parameters')
head.before = name
name.after = head
print('List added to Head')
return name
a = DoublyLinkedList(1)
b = DoublyLinkedList(2)
a.after = b
b.before = a
try:
addToHeadDLL(4, e)
except NameError as e:
print(e)
How can I print path outside function:
class FirstClas:
path = ''
def num(self):
path = "C:\\Users\\JOHN\\Desktop\\test.txt"
return path
print(path)
This method don't print anything.
This result:
C:\Python\python.exe C:/Users/JOHN/Desktop/test/tt.py
Process finished with exit code 0
You need to create an instance from the class that you created.
I would suggest doing this:
test = FirstClas()
print(test.num())
Hope this helps
Your method never gets called, and the class variable path is pointless here. Do:
class FirstClas:
def num(self):
path = "C:\\Users\\JOHN\\Desktop\\test.txt"
return path
print(FirstClas().num()) # note that this is outside the class!
I don't think you quite understand the purpose of classes, but here's how to make what you have "work" (in the sense that there are no fatal errors):
File global_variable.py
def init_global_variable():
"""initialize variable"""
global GLOBALS_DICT
GLOBALS_DICT = {}
def set_variable(name, value):
"""set variable"""
try:
GLOBALS_DICT[name] = value
return True
except KeyError:
return False
def get_variable(name):
"""get variable"""
try:
return GLOBALS_DICT[name]
except KeyError:
return "Not Found"
init_global_variable() # ADDED.
File tt.py
import os
#import lib.global_variable as glv
import global_variable as glv # Since I don't have your whole package.
class FirstClas:
def num(self):
path = "C:\\Users\\JOHN\\Desktop\\test.txt"
return path
def imag(self):
icon_file = os.path.join(
glv.get_variable("APP_PATH"),
glv.get_variable("DATA_DIR"),
"paths",
"PathExcel",
)
return icon_file
class Second:
# Put statements in a method so they don't run when the class is defined.
def run(self):
test = FirstClas()
print('first: ' + test.num())
print('second: ' + test.imag())
second = Second()
second.run()
Output:
first: C:\Users\JOHN\Desktop\test.txt
second: Not Found\Not Found\paths\PathExcel
the path does not changed(path = ' ') because you don't run the function num
When using click I know how to define a multiple choice option. I also know how to set an option as a required one. But, how can I indicate that an option B is required only if the value of option A is foo?
Here's an example:
import click
#click.command()
#click.option('--output',
type=click.Choice(['stdout', 'file']), default='stdout')
#click.option('--filename', type=click.STRING)
def main(output, filename):
print("output: " + output)
if output == 'file':
if filename is None:
print("filename must be provided!")
else:
print("filename: " + str(filename))
if __name__ == "__main__":
main()
If the output option is stdout, then filename is not needed. However, if the user chooses output to be file, then the other option filename must be provided. Is this pattern supported by click?
At the beginning of the function I can add something like:
if output == 'file' and filename is None:
raise ValueError('When output is "file", a filename must be provided')
But I am interested whether there's a nicer/cleaner solution.
In the particular case of this example, I think an easier method would be to get rid of --output, and simply assume stdout if --filename is not specified and if --filename is specified, then use it instead of stdout.
But assuming this is a contrived example, you can inherit from click.Option to allow hooking into the click processing:
Custom Class:
class OptionRequiredIf(click.Option):
def full_process_value(self, ctx, value):
value = super(OptionRequiredIf, self).full_process_value(ctx, value)
if value is None and ctx.params['output'] == 'file':
msg = 'Required if --output=file'
raise click.MissingParameter(ctx=ctx, param=self, message=msg)
return value
Using Custom Class:
To use the custom class, pass it as the cls argument to the option decorator like:
#click.option('--filename', type=click.STRING, cls=OptionRequiredIf)
Test Code:
import click
#click.command()
#click.option('--output',
type=click.Choice(['stdout', 'file']), default='stdout')
#click.option('--filename', type=click.STRING, cls=OptionRequiredIf)
def main(output, filename):
print("output: " + output)
if output == 'file':
if filename is None:
print("filename must be provided!")
else:
print("filename: " + str(filename))
main('--output=file'.split())
Results:
Usage: test.py [OPTIONS]
Error: Missing option "--filename". Required if --output=file
You can do the same thing with a custom validation callback:
import click
def required_with_output(ctx, param, value):
if ctx.params.get("output") != "stdout" and value is None:
raise click.BadParameter("--output requires --filename")
return value
#click.command()
#click.option(
"--output",
type=click.Choice(["stdout", "file"]),
default="stdout",
)
#click.option("--filename", callback=required_with_output)
def main(output, filename):
print("output: " + output)
if output == "file":
if filename is None:
print("filename must be provided!")
else:
print("filename: " + str(filename))
if __name__ == "__main__":
main()
I think this is a little simpler.
I extended the answer by Stephen, and made it more generic:
class OptionRequiredIf(click.Option):
"""
Option is required if the context has `option` set to `value`
"""
def __init__(self, *a, **k):
try:
option = k.pop('option')
value = k.pop('value')
except KeyError:
raise(KeyError("OptionRequiredIf needs the option and value "
"keywords arguments"))
click.Option.__init__(self, *a, **k)
self._option = option
self._value = value
def process_value(self, ctx, value):
value = super(OptionRequiredIf, self).process_value(ctx, value)
if value is None and ctx.params[self._option] == self._value:
msg = 'Required if --{}={}'.format(self._option, self._value)
raise click.MissingParameter(ctx=ctx, param=self, message=msg)
return value
Usage example:
#click.option('--email', type=click.STRING,
help='Settings for sending emails.',
option='output', value='email', cls=OptionRequiredIf)
I was inspired by this answer
I wanted to run code placed inside of thing.process upon when I hit the command.processCommand object (when i'm looping through all of the commands placed inside of defined[]), is there a way I can achieve this? This aforementioned loop will be executed as is such in myproject.py
command.py
class Command:
global defined
defined = []
def __init__(self, name):
self.name = name
self.description = "This command lacks a description"
self.args = ""
self.process = None
defined.append(self)
eightball.py
def processCommand():
print('hello')
thing = commands.Command('8ball')
thing.description = "Gives you a response from the mighty 8ball."
thing.process = processCommand
myproject.py
# Cogs
import cogs.commands as commands
import cogs.eightball
import cogs.helloworld
def processCommands(message):
if(message.content[:2] == "b#"):
args = message.content.split(' ')
args[0] = args[0][2:]
for command in defined:
if args[0] == command.name:
command.args = args
command.processCommand
for x in defined:
if x.process: # to skip `self.process = None`
x.process()
EDIT: you need process() instead of processCommand
for command in defined:
if args[0] == command.name:
command.args = args
command.process()