How to import a module as __main__? - python

I have a module that has the usual
if __name__ == '__main__':
do stuff...
idiom.
I'd like to import that from another module, and fool it into running that code. Is there any way of doing this?
I should mention, for reasons I won't go into here, I'm not in a position to change the code in the imported module. I need to somehow modify the import procedure so that it's name is main when imported, perhaps using ihooks or similar.

As pointed out in the other answers, this is a bad idea, and you should solve the issue some other way.
Regardless, the way Python does it is like this:
import runpy
result = runpy._run_module_as_main("your.module.name"))

There is, execute the script instead of importing it. But I consider this an extremely hackish solution.
However the ideal pattern would be:
def do_stuff():
... stuff happens ...
if __name__ == '__main__':
do_stuff()
that way you can do:
from mymodule import do_stuff
do_stuff()
EDIT: Answer after clarification on not being able to edit the module code.
I would never recommend this in any production code, this is a "use at own risk" solution.
import mymodule
with open(os.path.splitext(mymodule.__file__)[0] + ".py") as fh:
exec fh.read()

Put that code in a function, and call it from the module you are importing it into as well.
def stuff():
...
if __name__ == '__main__':
stuff()
And then in the module you are importing it into:
import module
module.stuff()

The correct answer has been already given however it is confined in a comments (see How to import a module as __main__?
and How to import a module as __main__?).
The same with proper formatting:
import runpy
runpy.run_module("your.module.name", {}, "__main__")
or
import runpy
runpy.run_path("path/to/my/file.py", {}, "__main__")

Code in a main stanza usually never makes sense to run directly. If you want to run it then use subprocess to run it in another Python interpreter.

Here is an example of a main module in Python:
#! /usr/bin/env python
import sys
import os
def main(arg1, arg2, arg3):
print(arg1, arg2, arg3)
if __name__ == "__main__":
main(*sys.argv)
But you can also include
def main():
#The module contains Python code specific to the library module,
#like tests, and follow the module with this:
if __name__ == "__main__":
main(*sys.argv)
in any module you would like to run as main.
For example, if you have a library module, you can always use this construct to execute something specific like tests.

Put it in a function:
def _main():
do stuff
if __name__ == '__main__':
main()

Related

How to handle logging and imports when running a python module as the main script?

I have a python library/package that contains modules with functions & classes I usually import inside of my application's main script. However, these modules each contain their own 'main()' function so that I can run them individually if needed. Here's an example:
# my_module.py
import logging
log = logging.getLogger(__name__)
class SomeModuleClass:
def __init__(self):
pass
def some_module_function():
pass
def main():
# Some code when running the module as the main script
if __name__ == "__main__":
main()
I have two questions related to running this module as the main script (i.e. running python my_module.py):
What's the cleanest way to use the logging module in this case? I usually simply overwrite the global 'log' variable by including the following in the main() function, but I'm not sure if there's a more pythonic way of doing this:
def main():
# ... some logging setup
logging.config.dictConfig(log_cfg_dictionary)
global log
log = logging.getLogger(__name__)
Is it considered good practice to include import statements inside of the main() function for all libraries only needed when running the script as main? For instance, one might need to use argparse, json, logging.config, etc. inside of the main function, but these libraries are not used anywhere else in my module. I know the most pythonic way is probably to keep all the import statements at the top of the file (especially if there's no significant difference in terms of memory usage or performance), but keeping main function-specific imports inside of main() remains readable & looks cleaner in my opinion.

restarting main.py without circular import error

I am trying to restart my main.py after the program has finished running. However, when I go into the last file (unlock.py) then put at the end of the script:
from main import *
main()
I get a circular import error. I am not sure a way to work around this so if anyone knows, your help would be greatly appreciated. If you have any questions, feel free to ask.
You can use the execv method of os module:
import os
import sys
os.execv(__file__, sys.argv)
If you're getting any permission errors:
os.execv(sys.executable,
[sys.executable, os.path.join(sys.path[0], __file__)] + sys.argv[1:])
To disable warnings:
import warnings
warnings.filterwarnings("ignore")
Without seeing the structure of your program, the best recommendation I can give is to pass your main function around as an argument. That way, in unlock.py, you don't need to import the main module.
Consider this simple example:
main.py
import unlock
def main(function_to_pass):
# do stuff
unlock.some_func(function_to_pass,*rest_of_args)
if __name__ == '__main__':
main(main)
unlock.py
def some_func(function_to_call,*args):
# do stuff
if some_condition:
function_to_call()
EDIT: I realized that you don't need to pass main into itself. main can simply reference itself. That is,
def main():
# do stuff
unlock.some_func(main,*args)

Python: How to Call Module from Other Path With __name__ == '__main__'

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?
There are multiple ways to approach this problem.
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.
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.)

Import a function from a module without module's dependencies

I would like to import a function foo() from module abc.py
However, abc.py contains other functions which rely on modules which are not available for Python (i.e. I cannot import them into python interpreter, because I use ImageJ to run abc.py as Jython)
One solution I found is to put the problematic imports inside the name == "main" check, such as:
# abc.py
def foo():
print("Hello, World!")
def run_main_function():
foo()
...other stuff using IJ...
if __name__ == "__main__":
from ij import IJ
run_main_function()
So when I try to import foo from into another script def.py, e.g.:
# def.py
from abc import foo
def other_func():
foo()
if __name__ == "__main__":
other_func()
This works. But when I put imports in normal fashion, at the top of the script, I get an error: No module named 'ij'. I would like to know if there is a solution to this problem? Specifically, that I put the imports at the top of the script and then within def.py I say to import just the function, without dependencies of abc.py?
I would like to know if there is a solution to this problem? Specifically, that I put the imports at the top of the script and then within def.py I say to import just the function, without dependencies of abc.py?
As far I know, it's the way that python works. You should put that import in the function that uses it if won't be aviable always.
def run_main_function():
from ij import IJ
foo()
Also, don't use abc as a module name, it's a standard library module: Abstract Base Class 2.7, Abstract Base Class 3.6
Edit: don't use trailing .py when importing as Kind Stranger stated.

How to write a script / library within the same file?

I want to implement certain functionality using python that can be used in two ways:
as simple command line script, like python mylib.py
by importing into other python code
My first attempts look like this.
mylib.py:
from __future__ import print_function
import sys
class A(object):
def __init__(self, args):
print("my args: {}".format(args))
def main():
a = A(sys.argv)
print("got {}".format(a))
main()
Which I can directly invoke, or use elsewhere, like usage.py:
import mylib
mylib.A("bla")
That works, but it seems the import causes main() to be executed as well:
python scripts/using.py blub
my args: ['scripts/using.py', 'blub']
got <mylib.A object at 0x7ff17bc736d0>
my args: bla
Questions:
Is there a way to prevent main() from running when I go for python using.pl?
And beyond that:
Is this a good approach? Or are there well established best practices in python that I am violating here?
In other words: are there things I should do differently?
This is why you add
if __name__ == '__main__':
main()
If this .py file is directly invoked, your main will run. If your file is simply imported, it will not run main. See here
Since #CoryKramer has already answered the first part of the question, let me take a shot at the second part.
Code should exists where it belongs. If it has anything to do with parsing the script or the main execution, then it should be in the script. Any other piece of code shouldn't be the part of script file.
Generally, in production code, you should never import from a script file. The common code should exist in it's own class in a separate file or just in a separate file in case of procedural approach. This way the code in your script would be succinct and the code in the common file is reusable in other production code and you won't run a risk of accidentally executing a script, just to use the common code.
# common.py
class A(object):
def __init__(self, args):
print("my args: {}".format(args))
# mylib.py
from common import A
if __name__ == '__main__':
a = A(sys.argv)
print("got {}".format(a))

Categories