1

I have two python scripts A and B, both with a main and with different input arguments (I use argparse). I launch them normally with:

$ python A.py --paramA1 valA1 --paramA2 valA2
$ python B.py --paramB1 valB1 --paramB2 valB2

I'd like to be able to call B from within A and to specify B's parameters when launching A. In short, I want to call A with A's parameters and B's parameters. Here's what it should look like from the outside:

$ python A.py --paramA1 valA1 --paramA2 valA2 --paramB1 valB1 --paramB2 valB2

Is there a more elegant way to do this than copying and pasting B's argparse code into A and then calling B on them?

EDIT: To simplify things, here's some example code:

A.py:

import argparse
def main():
    parser = argparse.ArgumentParser(description="Args for A.py")
    parser.add_argument("--param1A", type=int)
    parser.add_argument("--param2A", type=int)
    args = parser.parse_args()
    valA1 = args.param1A
    valA2 = args.param2A
    ...
    return 0

B.py:

import argparse
def main():
    parser = argparse.ArgumentParser(description="Args for B.py")
    parser.add_argument("--param1B", type=int)
    parser.add_argument("--param2B", type=int)
    args = parser.parse_args()
    valA1 = args.param1B
    valA2 = args.param2B
    ...
    return 0

What exactly would the suggested C.py, which includes arguments for both A.py and B.py look like? And what would A.py and B.py look like then?

EDIT 2: I forgot to mention that one of the parameters of B.py has to be created in A.py, so the order of execution is A then B, and A has to be able to pass a parameter to B.

1
  • 2
    I think an elegant solution here would be to wrap the argument parsing in to a third file. Commented Apr 8, 2013 at 9:47

2 Answers 2

2

You can create a module C.py which contains the common argparse logic and is imported by both A and B.

When calling B from A, you could also pass B the already parsed args. I mean, both A and B should have something like a main function which takes the already parsed args, therefore not having to do the parsing twice.

C.py

import argparse

def create_parser():
    parser = argparse.ArgumentParser(description="Args for B.py")
    parser.add_argument("--param1B", type=int)
    parser.add_argument("--param2B", type=int)
    return parser

B.py

import argparse
import sys
import C

def main(args):
    valB1 = args.param1B
    valB2 = args.param2B
    # do stuff
    return 0

if __name__ == '__main__':
    parser = C.create_parser()
    args = parser.parse_args()
    sys.exit(main(args))

A.py

import argparse
import sys
import C
import B

def main(args):
    valA1 = args.param1A
    valA2 = args.param2A
    # do stuff
    return 0


if __name__ == '__main__':
    parser = C.create_parser()
    parser.add_argument("--param1A", type=int)
    parser.add_argument("--param2A", type=int)
    args = parser.parse_args()
    B.main(args)
    sys.exit(main(args))
Sign up to request clarification or add additional context in comments.

8 Comments

Thanks. Could you give me an example based on the code provided in my (now) edited question? I don't understand how I should modify A.py and B.py if I write this new module C.py.
You can even bypass C altogether and put create_parser in B, which is then imported by A
Thanks a lot! One small thing: is it correct when under if __name__ == '__main__': you write return main(args)? I am getting SyntaxError: 'return' outside function, which points to the fact that I am not inside a function in that block of code. Should I just do sys.exit(main(args))?
Ahh, missed that. Indeed, sys.exit should be used. I'll edit the response.
That makes things quite different. My overall feeling is that you're trying to make things more complicated that they should be. I would rather go for the Unix philosophy and try to build short, simple scripts, with clear interfaces, which can then be chained together through pipes and/or xargs.
|
1

I think what @Ioan Alexandru Cucu described is something like the following:

import argparse

class A():
    __init__(self, param1A, param2A, param1B=None, param2B=None):
        if(param1B and param2B):
            myB = B(param1B, param2B)
        #Do processing here ...
        return 0


class B():
    __init__(self, param1B, param2B):
        #Do processing here ...
        return 0

if(__name__ == '__main__'):
    parser = argparse.ArgumentParser(description="Args for A and/or B")

    parser.add_argument("--param1A", type=int)
    parser.add_argument("--param2A", type=int)

    parser.add_argument("--param1B", type=int)
    parser.add_argument("--param2B", type=int)

    args = parser.parse_args()

    if(args.param1A and args.param2A and args.param1B and args.param2B):
        A(args.param1A, args.param2A, args.param1B, args.param2B)
    if(args.param1A and args.param2A):
        A(args.param1A, args.param2A)
    elif(args.param1B and args.param2B):
        B(args.param1B, args.param2B)

Instead of having multiple classes in one module you can have multiple modules with the different classes in them.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.