构建 python 模块,因此它可以从命令行 运行 使用和不使用 -m 开关
Structuring python module so it can be run from a command line with and without -m switch
背景
我正在研究 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
Returns
ImportError: No module named 'utilities'
而
python my_module --help
工作没有问题
期望的结果
- 以语句
python my_module
和 python -m my_module
都有效的方式构建导入。
- 交互式工作时不中断
import my_module
(奖金) 运行 无需先由 ./my_module --help
调用 python
解释器。我不确定如何使用 tree:
|-- my_module
| |-- my_module.py
| |-- __init__.py
| |-- __main__.py
| |-- module_component_A.py
| |-- utilities.py
是否有特定内容应该转到 my_module.py
?
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__
请注意,后者需要安装您的模块或直接与您的脚本相邻。如果您的模块可以安装,console_scripts
entry_point
允许自动创建这样的脚本。
您不应将脚本驻留在您的包中 - 这需要您将 sys.path
更改为父目录,这可能会导致重复的模块。例如,utilities.py
可作为单独的模块 my_module.utilities
和 utilities
.
背景
我正在研究 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
Returns
ImportError: No module named 'utilities'
而
python my_module --help
工作没有问题
期望的结果
- 以语句
python my_module
和python -m my_module
都有效的方式构建导入。 - 交互式工作时不中断
import my_module
(奖金) 运行 无需先由
./my_module --help
调用python
解释器。我不确定如何使用 tree:|-- my_module | |-- my_module.py | |-- __init__.py | |-- __main__.py | |-- module_component_A.py | |-- utilities.py
是否有特定内容应该转到
my_module.py
?
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__
请注意,后者需要安装您的模块或直接与您的脚本相邻。如果您的模块可以安装,console_scripts
entry_point
允许自动创建这样的脚本。
您不应将脚本驻留在您的包中 - 这需要您将 sys.path
更改为父目录,这可能会导致重复的模块。例如,utilities.py
可作为单独的模块 my_module.utilities
和 utilities
.