-2

As described in this answer how to import module one can import a module located in another path this way:

import sys
sys.path.append('PathToModule')
import models.user

My question is:

How can I execute this other module (and also pass parameters to it), if this other module is setup this way:

if __name__ == '__main__':
    do_something()

and do_something() uses argparse.ArgumentParser to work with the parameters supplied?

I ADDED THE FOLLOWING AFTER THE FIRST QUESTIONS/COMMENTS CAME UP

I am able to pass the parameters via

sys.argv[1:] = [
    "--param1", "123",
    "--param2", "456",
    "--param3", "111"
]

so this topic is already covered.

Why do I want to call another module with parameters?

I would like to be able to do a kind of a small regression test for another project. I would like to get this other project via a git clone and have different versions locally available, that I can debug, too, if needed.

But I do not want to be involved too much in that other project (so that forking does not make sense).

AND SO MY REMAINING QUESTION IS

How can I tweak the contents of __name__ when calling the other module?

  • Presumably you can write around the `argparse` bit. What exactly is it doing? – khelwood Mar 29 '18 at 22:35
  • A nicely-designed module (which is intended to be used this way) will argparse things into a set of arguments to pass to that `do_something` function, in which case you just call `module.do_something` with the right arguments. – abarnert Mar 29 '18 at 22:48
  • If the module wasn't intended to be used this way, it may be that the right answer is to launch it as a `subprocess` instead. – abarnert Mar 29 '18 at 22:49
  • If it is meant to work this way, but just wasn't designed very carefully, you can usually either fake out argparse in some way (if worst comes to worse hackily setting `sys.argv` or monkeypatching the module) or copy/paste the same work the top-level script code does (but simplified to only handle your case). Ugly, but the fix is to improve the other module. – abarnert Mar 29 '18 at 22:51
  • so my question is: how can I tweak the contents of `__name__` when it gets supplied to the module I would like to call –  Mar 29 '18 at 22:51
  • That's really a whole new question, but the short answer is that you can't. (Well, you _can_, by installing an import hook, or by modifying the source code of the other module before importing it, or by doing [even more horrible things that only a lunatic would explain how to do](https://stackoverflow.com/questions/49271750/is-it-possible-to-hack-pythons-print-function/49272080#49272080)… but that's not the right answer.) – abarnert Mar 29 '18 at 23:00

1 Answers1

1

There are multiple ways to approach this problem.

  1. If the module you want to import is well-written, it should have separate functions for parsing the command line arguments and for actually doing work. It should look something like this:

    def main(arg1, arg2):
        pass  # do something
    
    def parse_args():
        parser = argparse.ArgumentParser()
        ... # lots of code
        return vars(parser.parse_args())
    
    if __name__ == '__main__':
        args = parse_args()
        main(**args)
    

    In this case, you would simply import the module and then call its main function with the correct arguments:

    import yourModule
    yourModule.main('foo', 'bar')
    

    This is the optimal solution.

  2. If the module doesn't define such a main function, you can manually set sys.argv and use runpy.run_module to execute the module:

    import runpy
    import sys
    
    sys.argv[1:] = ['foo', 'bar']
    runpy.run_module('yourModule', run_name='__main__', alter_sys=True)
    

    Note that this only executes the module; it doesn't import it. (I.e. the module won't be added to sys.modules and you don't get a module object that you can interact with.)

Aran-Fey
  • 39,665
  • 11
  • 104
  • 149