You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Python跨平台控制台脚本部署疑问:scripts与console_scripts适配问题

解决pip install .console_scripts可执行脚本路径问题

我来帮你分析下这个问题的根源,再给你两个可行的解决方案——核心原因其实是开发模式和正常安装模式下Python路径的差异:

  • 当你用pip install -e .(开发模式)时,你的项目根目录会被直接添加到Python的sys.path里,所以哪怕scripts目录不是一个正式的Python包,Python也能找到里面的脚本模块;
  • 但用pip install .正常安装时,只有my_package会被安装到系统的site-packages目录,scripts目录默认不会被打包进去,这就导致你通过console_scripts配置的入口点找不到对应的模块了。

推荐方案:规范打包结构,将脚本逻辑迁移到package内

这是Python打包的最佳实践,既能完美解决跨平台问题,也方便后续维护:

  1. my_package里新建一个专门处理命令行入口的模块,比如cli.py

    # my_package/cli.py
    # 导入你package里的核心功能
    from .modules import your_function_here
    
    def abc_main():
        # 这里放原来scripts/abc里的所有逻辑,或者直接调用核心功能
        print("Executing abc command")
        # your_function_here()
    
    def def_main():
        # 同理处理scripts/def的逻辑
        print("Executing def command")
    
  2. 修改setup.pyentry_points配置,指向这个新模块的函数:

    # setup.py
    from setuptools import setup, find_packages
    
    setup(
        name="my_package",
        version="0.1.0",
        packages=find_packages(),
        entry_points={
            "console_scripts": [
                "abc=my_package.cli:abc_main",
                "def=my_package.cli:def_main"
            ]
        }
    )
    
  3. 现在不管是开发模式还是正常安装,abcdef命令都能正常运行了——因为console_scripts会自动生成对应平台的可执行文件(Windows下是.exe,Linux/macOS是可执行脚本),而且这些生成的文件会正确指向安装在site-packages里的my_package.cli模块,完全没有路径问题。

  4. 如果想保留原来的scripts目录做本地测试,可以把原脚本改成简单的调用 wrapper:

    # scripts/abc
    #!/usr/bin/env python3
    from my_package.cli import abc_main
    abc_main()
    

    这样本地运行脚本也能正常工作,同时不影响安装后的命令。


备选方案:将scripts目录作为Python包打包(不推荐)

如果你实在不想移动脚本逻辑,可以把scripts目录改成一个正式的Python包,让它被一起安装到site-packages:

  1. scripts目录下添加__init__.py(空文件即可),并把原来的abcdef脚本改成带.py后缀的文件(比如abc.py):

    working folder
    ├── my_package
    │   ├── __init__.py
    │   ├── modules.py
    ├── scripts
    │   ├── __init__.py
    │   ├── abc.py
    │   └── def.py
    └── setup.py
    
  2. 修改脚本文件,添加main()函数(因为console_scripts需要指向一个可调用的函数):

    # scripts/abc.py
    def main():
        # 原来的脚本逻辑
        print("Running abc script")
    
    if __name__ == "__main__":
        main()
    
  3. 修改setup.py,把scripts包包含到安装内容中:

    # setup.py
    from setuptools import setup, find_packages
    
    setup(
        name="my_package",
        version="0.1.0",
        packages=find_packages(include=["my_package", "scripts"]),
        entry_points={
            "console_scripts": [
                "abc=scripts.abc:main",
                "def=scripts.def:main"
            ]
        }
    )
    

这样安装后scripts包会被放到site-packages里,console_scripts的入口点就能找到对应的模块了。不过这种方式会把脚本逻辑和核心代码分离,长期来看不利于维护,所以还是推荐第一种方案。

内容的提问来源于stack exchange,提问作者Ryan

火山引擎 最新活动