Access function from within scripts and from commandline - python

I want to do the following:
I have a class which should provide several functions, which need different inputs. And I would like to use these functions from within other scripts, or solely from commandline.
e.g. I have the class "test". It has a function "quicktest" (which basically justs prints something). (From commandline) I want to be able to
$ python test.py quicktest "foo" "bar"
Whereas quicktest is the name of the function, and "foo" and "bar" are the variables.
Also (from within another script) I want to
from test import test
# this
t = test()
t.quicktest(["foo1", "bar1"])
# or this
test().quicktest(["foo2", "bar2"])
I just can't bring that to work. I managed to write a class for the first request and one for the second, but not for both of them. The problem is that I sometimes have to call the functions via (self), sometimes not, and also I have to provide the given parameters at any time, which is also kinda complicated.
So, does anybody have an idea for that?
This is what I already have:
Works only from commandline:
class test:
def quicktest(params):
pprint(params)
if (__name__ == '__main__'):
if (sys.argv[1] == "quicktest"):
quicktest(sys.argv)
else:
print "Wrong call."
Works only from within other scripts:
class test:
_params = sys.argv
def quicktest(self, params):
pprint(params)
pprint(self._params)
if (__name__ == '__main__'):
if (sys.argv[1] == "quicktest"):
quicktest()
else:
print "Wrong call"

try the following (note that the different indentation, the if __name__ part is not part of class test anymore):
class test:
def quicktest(params):
pprint(params)
if __name__ == '__main__':
if sys.argv[1] == "quicktest":
testObj = test()
testObj.quicktest(sys.argv)
else:
print "Wrong call."
from other scripts:
from test import test
testObj = test()
testObj.quicktest(...)

The if __name__ == '__main__': block needs to be at the top level:
class Test(object): # Python class names are capitalized and should inherit from object
def __init__(self, *args):
# parse args here so you can import and call with options too
self.args = args
def quicktest(self):
return 'ret_value'
if __name__ == '__main__':
test = Test(sys.argv[1:])

You can parse the command line with the help of argparse to parse the value from the command line.
Your class which has the method and associate methods to arguments.

Related

How to pass input argument from one python file to another

To simplify the problem, lets say I have 4 files. And right now I arrange them like the following
main.py (where I start the program)
global important_arg
important_arg = sys.argv[1]
if __name__ == "__main__":
import worker_a
import worker_b
if important_arg == "0":
worker = worker_a.worker()
worker.run()
elif important_arg == "1":
worker = worker_b.worker()
worker.run()
worker_a/worker_b.py
import main
import helper
class worker:
def run(self):
a = helper.dosth()
b = helper.dosth_2()
....blah blah blah
helper.py (where worker_a and b both needed static function)
import main
important_arg = main.important_arg #This is not work I know, the problem is how to make this work.
def dosth():
...
#I have tiny part need important_arg
if important_arg == "0":
print "This is worker A."
elif important_arg == "1":
print "This is worker B."
...
def dosth_2():
...
For sure in this pattern, my helper.py can no longer retrieve the important_arg from the main.py.
If I force it to run, no surprise,
The error will be
'module' object has no attribute 'important_arg'
How should I redesign the pattern, or anyway to pass that arg from the main.py to helper.py?
Besides, my last method is to covert the whole helper.py into a 'class'. But this is tedious as I need to add back tons of 'self.', unless I find passing the variable is impossible, I am unlikely to use this method right now.

Use embedded argparse in Python3

I want to make a Python module that can be used both by command line and other modules.
Like that :
python3 Capacity.py arg1 arg2 arg3
or
>>> capacity.execByString("arg1 arg2 arg3")
I made a class to (with some researches) get the result of argparse within the code :
class ArgumentParserError(Exception): pass
class Parseur(ArgumentParser):
def error(self, msg):
raise ArgumentParserError(msg)
def analyze(self, args):
if type(args) is not list:
args = args.split() # To work with a String
try:
result = self.parse_args(args)
return True, result
# Returns True and the namespace if OK
except ArgumentParserError as err:
return False, err.args[0]
# Returns False and the error message if not OK
I use it like this :
class Capacity():
def __init__(self):
self.parser = Parseur()
# Config the parser
def execByArguments(*args):
# Do the job
def execByString(command):
isOK, result = self.parser.analyze(command)
if isOk:
# Launch execByArguments with the rights args in result
else:
# Print error message
print(result)
def execFromCommandLine():
args = self.parser.parse_args()
# Launch execByArguments with the rights args
if __name__ == "__main__":
execFromCommandLine()
But there's 2 main problems and surely some I have'nt yet discovered :
the args are not parsed correctly (doubles quotes for example) as the split function has the "spaces" separator
using the -h flag close the program anyway
I'm convinced that making this another Parseur class is useless/not good and there's a workaround.
Launching the module via subprocess is not a good idea neither : I want to get the returned object in that case.
Can you help me to find a cool way to do what i want please ?
Thanks already.
PS : Write code on the online formular is such a pain ^^.
You are not far away. I would do it somehow like this:
class Capacity():
def __init__(self, argv):
# take over and store arguments (or process further parsing)
self.parser = Parseur()
isOk, result = self.parser.analyze(argv)
def argInputValidation(argv):
#checking the command line arguments given by user
#and returning valid argv, otherwise exit program
#with an error message.
return argv
if __name__ == "__main__":
obj = Capacity(argInputValidation(sys.argv[1:]))

Changes made to object attribute not seen when using the multiprocessing module

When using multiprocessing in Python, and you're importing a module, why is is that any instance variables in the module are pass by copy to the child process, whereas and arguments passed in the args() parameter are pass by reference.
Does this have to do with thread safety perhaps?
foo.py
class User:
def __init__(self, name):
self.name = name
foo_user = User('foo')
main.py
import multiprocessing
from foo import User, foo_user
def worker(main_foo):
print(main_foo.name) #prints 'main user'
print(foo_user.name) #prints 'foo user', why doesn't it print 'override'
if __name__ == '__main__':
main_foo = User('main user')
foo_user.name = 'override'
p = multiprocessing.Process(target=worker, args=(main_foo,))
p.start()
p.join()
EDIT: I'm an idiot, self.name = None should have been self.name = name. I made the correction in my code and forgot to copy it back over.
Actually, it does print override. Look at this:
$ python main.py
None
override
But! This only happens on *Nix. My guess is that you are running on Windows. The difference being that, in Windows, a fresh copy of the interpreter is spawned to just run your function, and the change you made to foo_user.name is not made, because in this new instance, __name__ is not __main__, so that bit of code is not executed. This is done to prevent infinite recursion.
You'll see the difference if you add this line to your function:
def worker(main_foo):
print(__name__)
...
This prints __main__ on *Nix. However, it will not be __main__ for Windows.
You'll want to move that line out of the if __name__ == __main__ block, if you want it to work.

Query on entry point annotation in python

I am trying to understand the usage of #main annotation in python.
With the below python program,
def cube(x):
return x * x * x
def run_tests():
printf("Should be 1:", cube(1))
printf("Should be 8:", cube(2))
printf("Should be 27:", cube(3))
#main
def main():
print("Starting")
run_tests()
print("Ending.")
I get the following error:
PS C:\Users\MOHET01\Desktop> python.exe -i .\cube.py
Traceback (most recent call last):
File ".\cube.py", line 9, in <module>
#main
NameError: name 'main' is not defined
>>>
Function that is imported from ucb is as shown below:
def main(fn):
"""Call fn with command line arguments. Used as a decorator.
The main decorator marks the function that starts a program. For example,
interact()
#main
def my_run_function():
# function body
Use this instead of the typical __name__ == "__main__" predicate.
"""
if inspect.stack()[1][0].f_locals['__name__'] == '__main__':
args = sys.argv[1:] # Discard the script name from command line
print(args)
print(*args)
print(fn)
fn(*args) # Call the main function
return fn
My question:
Despite i define function with intrinsic name main, Why do i see this error?
I should use this:
def main():
#Do something
if __name__ == "__main__":
#Here use the method that will be the main
main()
I hope this helps
The #main decorator is implemented in a file your course provides, but you have not imported it. The page you linked says to use
from ucb import main, interact
to import the ucb.py features in your program.
As for why the error says name 'main' is not defined, that's because the function definition doesn't actually finish defining anything until the decorators execute. The reuse of the name main for both the decorator and the decorated function is confusing; the main in #main is a different function from the main you're defining in def main(): .... The main in #main is defined to run the decorated function if the file is run as a script, while the main in def main(): ... is the function to be run.
I would strongly recommend not using anything like this decorator when you don't have to. The standard way to perform the task the decorator performs is to write
if __name__ == '__main__':
whatever_function_you_would_have_put_the_decorator_on()
or if you want to handle command line arguments like the decorator would,
if __name__ == '__main__':
import sys
whatever_function_you_would_have_put_the_decorator_on(*sys.argv[1:])
The decorator is an attempt to hide the issues of sys.argv and __name__ so you don't have to know about them, but it has a problem. If you try to write something like this:
#main
def hello():
print(hello_string)
hello_string = 'Hi there.'
you'll get a NameError, because hello_string won't be assigned until after the decorator runs. If you continue to write Python beyond this course, you'll find that using if __name__ == '__main__' is less bug-prone and more understandable to other programmers than using a decorator for this.
You are using the function before it is defined. In other words, you need to define the main function higher up (in the document) than where you use it as a decorator:
def main():
pass
#main
def somefunction():
pass
The #main notation means the main function is being used to "decorate", or modify, another function. There are various articles on python decorators:
http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/
http://www.artima.com/weblogs/viewpost.jsp?thread=240808
http://www.jeffknupp.com/blog/2013/11/29/improve-your-python-decorators-explained/
You can only use a decorator on a different function. Example:
def foo(f):
def inner():
print("before")
f()
print("after")
return inner
#foo
def bar():
print("bar")
if __name__ == "__main__":
bar()
Output:
before
bar
after

How do I execute a module's code from another?

I know it's a greenhorn question. But. I have a very simple module that contains a class, and I want to call the module to run from another. Like so:
#module a, to be imported
import statements
if __name__ == '__main__':
class a1:
def __init__(self, stuff):
do stuff
def run_proc():
do stuff involving 'a1' when called from another module
#Module that I'll run, that imports and uses 'a':
if __name__ == '__main__':
import a
a.run_proc()
However, for reasons that are likely obvious to others, I get the error Attribute Error: 'Module' object has no attribute 'run_proc' Do I need a static method for this class, or to have my run_proc() method within a class, that I initialize an instance of?
Move the
if __name__ == '__main__':
in module a to the end of the file and add pass or some test code.
Your problems are that:
Any thing in the scope of if __name__ == '__main__': is only considered in the top level file.
You are defining a class but not creating a class instance.
module a, to be imported
import statements
class a1:
def __init__(self, stuff):
do stuff
def run_proc():
#do stuff involving 'a1' when called from another module
if __name__ == '__main__':
pass # Replace with test code!
Module that I'll run, that imports and uses 'a':
import a
def do_a():
A = a.a1() # Create an instance
A.run_proc() # Use it
if __name__ == '__main__':
do_a()

Categories