-2

I have a module, called T, has a couple of functions and the main part, where calls these functions. From another module, I want to use this module. The main scheme is like:

"""Module T"""
def parse_args():
    parser = argparse.ArgumentParser(description='Desc')
    parser.add_argument('something')

def foo():
    pass

if __name__ == "__main__":
    args = parse_args()
    foo()

And the other module I want to use:

"""Module M"""
def foo():
    pass

def do_something():
    """Where I want to use module T's main"""

I have used module T from terminal with arguments and worked fine. The question may be easy but, how can I use it's main with parameters?

emremrah
  • 1,733
  • 13
  • 19
  • If you really need to call its main, I think the only way to do it is calling it as an external program. But why would you want to call its main in the first place? Why not simply calling `T`s methods inside directly? – Tobias Brösamle Nov 16 '18 at 13:58
  • Seems like the easiest solution might just be to pull those two lines into a `main()` function inside `T`, then call `main()` both from `T` and from `M`. – 0x5453 Nov 16 '18 at 13:58
  • @TobiasBrösamle I'm new to python and it's logic about main. I have searched an answer to this but didn't find any. I thought a solution as the same as 0x5453's but insisted to find an easier way. You both of you might be right. – emremrah Nov 16 '18 at 14:02

2 Answers2

2

Add a run function (or main or whatever you like) to your module that accepts your command line, and make sure that parse_args optionally accepts an arbitrary list as well:

def parse_args(args=None):
    parser = argparse.ArgumentParser(description='Desc')
    parser.add_argument('something')
    return parser.parse_args(args)

def foo():
    pass

def run(args=None):
    args = parse_args(args)
    foo()

if __name__ == "__main__":
    run()

Basically, instead of trying to simulate the import operation and injecting sys.argv (which might actually be possible), you can just factor out the part that the import runs that's of interest to you, and provide access to it:

import T

T.run()  # Uses sys.argv
T.run(['my', 'list', '--of', 'args'])

While totally untested, you can possibly also do something like the following (please don't though, this is just for fun):

import sys
from importlib import reload

sys.argv[1:] = my_args

if 'T' in sys.modules:
    reload(sys.modules['T'])
else:
    import T

But then you'd need to remove the import guard in T.py. Unless you wanted to implement your own module loading sequence, which would let you inject T.__name__, rather than having to modify the import guard: Injecting variables into an import namespace

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
2

The if __name__ ... pattern is executed if the script is called directly, so the real solution is to call foo in your entrypoint. The if __name__ ... patter basically protects lines of code from being executed on import. For example, this is a very convenient pattern for testing - just put your tests in the protected block. The straightforward way to do what you're asking:

"""Module M"""
def bar():
    pass

def do_something(args):
    args = parse_args()
    module_t.foo()

If you want module M to be completely "fire and forget" then Mad Physicist's answer is for you.

Charles Landau
  • 4,187
  • 1
  • 8
  • 24