there is an executable main.py file who takes as argument a savefile, how can I check in an other class if the savefile was given over?
code main.py:
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="test")
parser.add_argument('--savefile', help="A savefile")
args = parser.parse_args()
if(args.savefile):
from A import A
a = A()
a.run() //executes the run function in A
class A.py
class A(){
def run():
import main
if(main.args.savefile):
//do sth
}
However I always seem to get the AttributeError: module 'main' has no attribute 'args'
Appreciate any help, ty.
You could use something like the following pattern to avoid dangerous imports.
The main change is in the class, where we declare the __init__ function to accept the parameter we will give in the main file.
#file A.py
class A():
def __init__(self, savefile=None):
self.savefile = savefile
def run(self):
if self.savefile:
# do sth
print(self.savefile)
# main.py
import argparse
from A import A
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="test")
parser.add_argument('--savefile', help="A savefile")
args = parser.parse_args()
if args.savefile:
a = A(args.savefile)
a.run()
Related
I'm writing a small utility function which takes in input arguments of the location of a Python file, and also a function to call within the Python file
For example src/path/to/file_a.py
def foo():
...
In the utility function, I'm parsing the arguments like so:
python ./util.py --path src/path/to/file_a.py --function foo
and the foo function needs to be used later in the util.py in another library:
def compile():
compiler.compile(
function=foo,
etc
)
What's the best way of importing the foo function via argparse?
Some initial thoughts:
util.py:
def get_args():
parser = argparse.ArgumentParser()
parser.add_argument("--path", type=str)
parser.add_argument("--function", type=str)
return parser.parse_args()
def compile(path, function):
import path
compiler.compile(
function=path.function,
etc
)
if __name__ == "__main__":
args = get_args()
compile(
path=args.path
function=args.function
)
however importing via argparse, and adding it to the function does not seem to work nicely.
There's also the idea of using sys.path.append:
def compile(path, function):
import sys
sys.path.append(path)
but then I'm unsure of how to import the foo function from that.
This problem can be rephrased as "how do I import a python file given a path?" To do that, we can use https://stackoverflow.com/a/67692/5666087. Here is a code example that incorporates the answer to that question with your needs.
import argparse
import importlib.util
import sys
def get_function_object(path_to_pyfile: str, funcname: str):
spec = importlib.util.spec_from_file_location("tmpmodulename", path_to_pyfile)
module = importlib.util.module_from_spec(spec)
sys.modules["tmpmodulename"] = module
spec.loader.exec_module(module)
if not hasattr(module, funcname):
raise AttributeError(f"Cannot find function '{funcname}'in imported module")
# TODO: Consider testing whether this object is a callable.
return getattr(module, funcname)
def get_args():
parser = argparse.ArgumentParser()
parser.add_argument("--path", type=str)
parser.add_argument("--function", type=str)
return parser.parse_args()
if __name__ == "__main__":
args = get_args()
function = get_function_object(args.path, funcname=args.function)
compiler.compile(function=funtion)
I'm trying to write a Python script to create a CLI command. To make it more readable, I'm creating argparse.ArgumentParser object directly in the class __init__() (not in the '__main__' part of the script as is usually the case in tutorials).
The approach included in the sample code below works but it looks messy.
I wonder whether this would be the correct way to do it or I should do something else. (Sorry for newbie question.)
import argparse
class Command:
def __init__(self, *args):
self.parser = argparse.ArgumentParser(usage='command [--first] [--second]', description='This is a sample command')
self.parser.add_argument('--first', type=str, required=True, help='first argument', dest='first_argument')
self.parser.add_argument('--second', type=str, required=True, help='second argument', dest='second_argument')
args = self.parser.parse_args()
self.first_argument = args.first_argument
self.second_argument = args.second_argument
def some_operation(self):
concatenated_str = self.first_argument + self.second_argument
return concatenated_str
if __name__ == '__main__':
command = Command() # creating class instance
print(command.some_operation())
Putting it in a separate class method in this way doesn't work and produces AttributeError:
# Code above
def set_params(self):
args = self.parser.parse_args()
self.first_argument = args.first_argument
self.second_argument = args.second_argument
return self.first_argument, self.second_argument
# Code below
I have a simple code that needs at least 1 argument. Right now my code format looks something like this:
import modules
# argparse stuff
parser = argparse.ArgumentParser()
parser.add_argument(-m)
parser.add_argument(-u)
args = parser.parse_args()
# check the number of arguments
if len(sys.argv) > 3:
sys.exit()
if len(sys.argv) == 1:
sys.exit()
class Program:
def A():
def B():
def C():
if __name__ == '__main__':
try:
Program()
The code works as intended, but I'd like to know how I can rewrite my code to be 'pythonic'. Do I put the argument checks under the 'if name' statement? If so, how? thanks.
I would suggest not looking at sys.argv, especially if you're already using a CLI parsing library.
Argprase has a pile of ways to enforce requirements, but if none of those fit your needs you can looks at your 'args' object.
Personally, I would suggest not running functions, like parse_args(), in the global scope of that file. Instead I would suggest (at minimum) to just wrap what you've got in a function called main, then call 'main()' after 'if __name__ == '__main__'
Argparse examples:
if '-m' and '-u' are mutually exclusive
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('-m')
group.add_argument('-u')
args = parser.parse_args() # will output a error message if '-m' or '-u' isn't supplied
If a specific arg is required always
parser = argparse.ArgumentParser()
parser.add_argument('-m', required=True) # must always give '-m'
Or just looking at the 'args' object
parser = argparse.ArgumentParser()
parser.add_argument('-m')
parser.add_argument('-u')
args = parser.parse_args()
if not (args.m or args.u):
sys.exit(1) # should exit non-zero on failures
main wrapping example:
import modules
class Program:
def A():
def B():
def C():
def main():
parser = argparse.ArgumentParser()
parser.add_argument(-m)
parser.add_argument(-u)
args = parser.parse_args()
if not (args.m or args.u):
sys.exit(1)
try:
Program()
except SomeException:
# handle it
pass # b/c I don't know what you need here
if __name__ == '__main__':
main()
Checking the number of arguments after argparse doesn't make much sense. If there's some error, argparse will handle that, so you don't really have to replicate it.
Do put the arguments check after if __name__ check - just in case you want to import the module without executing.
Otherwise, it's just standard code as you'd see in argparse documentation. Nothing really wrong with it.
I am trying to learn python i tried to import a class in another class but it is not working
Application.py:
class Application:
def example(self):
return "i am from Application class"
Main.py
class Main:
def main():
application = Application()
application.example()
if __name__ == "__main__":
Main.main()
This gives me :
File "Main.py", line 11, in <module>
Main.main()
TypeError: unbound method main() must be called with Main instance as first argument (got nothing instead)
The error has nothing to do with importing (Although you don't seem to import Application anywhere). The problem is that you use the main method like a static method without declaring it to be static.
To solve this, You either need to declare your main method as static or create an instance of the Main class.
As a static method (add the #staticmethod decorator):
class Main():
#staticmethod
def main():
...
With an Instance:
class Main():
def main(self):
....
if __name__ == "__main__":
myMain = Main() #create an instance
myMain.main() #call the function on the instance
Also, to import your Application class from Application.py, you would just write this:
from Application import Application
You should instantiate your Main class first.
if __name__ == '__main__':
myMain = Main()
myMain.main()
But this will give you another error:
TypeError: main() takes no arguments (1 given)
There are two ways to fix this. Either make Main.main take one argument:
class Main:
def main(self):
application = Application()
application.example()
or make Main.main a static method. In which case you don't have to instantiate your Main class:
class Main:
#staticmethod
def main():
application = Application()
application.example()
if __name__ == "__main__":
Main.main()
In a script I'm trying to import the main module from another script with an argument.
I get the error message "NameError: global name 'model' is not defined".
If someone sees the mistake, I'd be grateful !
My code :
script1
#!/usr/bin/python
import sys
import getopt
import pdb
import shelve
class Car:
""" class representing a car object """
def __init__(self, model):
self.model = model
class Porsche(Car):
""" class representing a Porsche """
def __init__(self, model):
Car.__init__(self, model)
print "I have a Porsche but no driving licence : too bad !"
# Main
def main(argv):
settings = shelve.open('mySettings')
global model
try:
opts, args = getopt.getopt(argv, "m:", ["model="])
except getopt.GetoptError, err:
print " wrong argument, exiting "
sys.exit()
for opt, arg in opts:
if opt in ("-m", "--model"):
model = arg
def choose_car(model):
""" Creates the car"""
my_Porsche = Porsche(model)
choose_car(model)
if __name__ == "__main__":
main(sys.argv[1:])
script2
#!/usr/bin/python
import os
import sample
import sys
def main(argv):
script1.main("-m Carrera")
# Main program
if __name__ == '__main__':
main(sys.argv[1:])
rgds,
argv is a list. Therefore you should call script1.main as
script1.main(['-m', 'Carrera'])
or, equivalently,
script1.main('-m Carrera'.split())