简体   繁体   中英

How to load a python module with arguments in python?

I would like to create a python module that would be called with python -m mymodule somefile.py some_arg some_arg .

The idea is that I would be able to set up an alias alias="python -m mymodule" and call files normally with python somefile.py some_arg some_arg .

In the file mymodule/__main__.py , what is the best way to load somefile.py and pass it the argument list?

  • I am looking for a generic solution, that would be python2 and 3 compatible.
  • It would be great to be as little intrusive as possible. If somefile.py would raise an exception, mymodule should barely be seen in the traceback.
  • What the module does is not interesting here in detail, but it sets up some python things (traceback hooks etc.), so somefile.py should be ran pythonicly in the same process. os.system or subprocess.Popen do not fit.

Ok I found something good for python 3.5, and satisfying enough for python 2.7.

mymodule/ main .py

import sys

# The following block of code removes the part of 
# the traceback related to this very module, and runpy
# Negative limit support came with python 3.5, so it will not work
# with previous versions.
# https://docs.python.org/3.5/library/traceback.html#traceback.print_tb
def myexcepthook(type, value, tb):
     nb_noise_lines = 3
     traceback_size = len(traceback.extract_tb(tb))
     traceback.print_tb(tb, nb_noise_lines - traceback_size)
if sys.version_info >= (3, 5):
    sys.excepthook = myexcepthook

if len(sys.argv) > 1:
    file = sys.argv[1]
    sys.argv = sys.argv[1:]

    with open(file) as f:
         code = compile(f.read(), file, 'exec')
         exec(code)

somefile.py

import sys
print sys.argv
raise Exception()

in the terminal

$ python3 -m mymodule somefile.py some_arg some_arg
['somefile.py', 'some_arg', 'some_arg']
Traceback (most recent call last):
  File "somefile.py", line 3, in <module>
    raise Exception()

$ python2 -m mymodule somefile.py some_arg some_arg
['somefile.py', 'some_arg', 'some_arg']
Traceback (most recent call last):
  File "/usr/lib64/python3.5/runpy.py", line 184, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/lib64/python3.5/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/home/azmeuk/dev/testpy/mymodule/__main__.py", line 16, in <module>
    exec(code)
  File "somefile.py", line 3, in <module>
    raise Exception()

$ python somefile.py some_arg some_arg
['somefile.py', 'some_arg', 'some_arg']
Traceback (most recent call last):
  File "somefile.py", line 3, in <module>
    raise Exception()
Exception

Still, if someone has a better proposition, it would be great!

I think the negative value of limit does not work in traceback module before python 3.5. Here is an ugly hack that works with python 2.7

import sys
import traceback

class ExcFile(object):
    def __init__(self, file):
        self.topline = True
        self.file = file

    def write(self, s):
        if self.topline:
            u, s = s.split('\n', 1)
            self.file.write(u +'\n')
            self.topline = False
        if '#---\n' in s:
            u, s = s.split('#---\n', 1)
            self.file.write(s)
            self.write = self.file.write

ExcFile._instance = ExcFile(sys.stdout)    
# The following block of code removes the part of 
# the traceback related to this very module, and runpy
def myexcepthook(type, value, tb):
    traceback.print_exception(type, value, tb, file=ExcFile._instance)
sys.excepthook = myexcepthook

if len(sys.argv) > 1:
    file = sys.argv[1]
    sys.argv = sys.argv[1:]

    with open(file) as f:
        code = compile(f.read(), file, 'exec')
        exec(code) #---

All this should be written in a separate file, to avoid clutter __main__.py .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM