构建python模块,以便可以在带有-m开关和不带有-m开关的情况下从命令行运行它

时间:2019-05-23 15:28:33

标签: python python-3.x command-line module python-import

背景

我正在研究由许多脚本组成的Python模块。最终目标是使模块中的功能在进行交互工作时可通过import语句导入,并通过命令行参数使模块的某些部分可执行。

所需结果

可以使用以下命令运行模块:

python -m ./my_module --help
# No -m switch
python ./my_module --help

结构

this answer之后,我想了解 -m 开关与__main__.py__init__.py文件之间的关系。当前的结构如下

__main__.py

# Shebang line


###########
# Modules #
###########
import argparse
import logging
import tempfile


###################
# Package modules #
###################
from utilities import check_directory_access
# ...


#################
# Run functions #
#################
def run(args):
    """Run all functions with provided arguments"""
    # Start logging configuration
    # If file is not provided use temporary file
    if args.log_file is None:
        args.log_file = tempfile.NamedTemporaryFile(delete=False,
                                                    prefix='my_module',
                                                    suffix='.log').name
    # Create handlers: console
    # logging configuration
    logging.shutdown()


def main():
    """Process arguments and run main function"""
    parser = argparse.ArgumentParser(description='Dop stuff module',
                                     epilog='Epilog')
    parser.add_argument("-t", "--tables", nargs='+', dest='tables',
                        help="List tables to refresh", type=str)
    parser.add_argument("-l", "--log-file", dest='log_file',
                        type=str, help="Log file")
    parser.set_defaults(func=run)
    args = parser.parse_args()
    args.func(args)

if __name__ == "__main__":
    main()

__init__.py

###################
# Package modules #
###################
from .utilities import check_directory_access
# Other components

问题

运行:

python -m my_module --help

返回

  

ImportError:没有名为“实用程序”的模块

python my_module --help

没有问题

所需结果

  • 以语句python my_modulepython -m my_module都起作用的方式构造导入。
  • 进行交互工作时不破坏import my_module
  • (奖励)在没有由python首先调用./my_module --help解释器的情况下运行。我不确定如何使用tree:

    |-- my_module
    |   |-- my_module.py
    |   |-- __init__.py
    |   |-- __main__.py
    |   |-- module_component_A.py
    |   |-- utilities.py
    

    是否有应转到my_module.py的特定内容?

1 个答案:

答案 0 :(得分:3)

Python 3没有隐含的相对导入。使用绝对或显式相对导入:

from .utilities import check_directory_access
from my_module.utilities import check_directory_access

这使您的程序包可以与-m开关一起使用。它还允许在交互式会话中使用import my_module


存储为文件夹的裸包无法直接执行。这是由于操作系统本身。如果要避免显式调用python,则必须创建一个运行程序包的可执行文件。

要么将软件包存储为可执行zip文件,要么创建运行您的软件包的脚本。

#!/usr/bin/env python3
import my_module.__main__

请注意,后面的版本要求您安装模块或直接将其与脚本相邻。

您不应将脚本驻留在软件包中-这要求您将sys.path更改为父目录,这可能导致重复的模块。例如,utilities.py将作为单独的模块my_module.utilities utilities可用。