You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python脚本作为.py文件正常运行,打包为pip包后失效如何排查?

问题:Python脚本打包为PyPI包后调用Copilot CLI生成空输出

本地直接运行.py脚本时,可正常调用Copilot CLI生成COBOL文档;但打包成pip包后,输出文件为空且生成速度异常快。已确认copilot命令可被程序找到,无法定位具体故障原因。


脚本代码

import argparse as ap
import os
import sys
import subprocess
import shutil 
from subprocess import PIPE
from tqdm import tqdm

# Main function
def main():
    # Parse command line arguments
    parser = ap.ArgumentParser(description="Automate COBOL documentation generation using Copilot.")
    parser.add_argument("-p","--Prompt",type=str,help="Prompt directory for Copilot to generate documentation.")
    parser.add_argument("-c","--Cobol",type=str,help="COBOL source code directory OR File to be documented.")
    parser.add_argument("-o","--Output",type=str,help="Output directory for generated documentation.")
    args = parser.parse_args()

    # Create variables for paths and validate them
    prompt_path = args.Prompt
    cobol_path = args.Cobol
    output_path = args.Output

    if not os.path.exists(prompt_path):
        print(f"Error: Prompt path '{prompt_path}' does not exist.")
        sys.exit(1)
    
    if not os.path.exists(cobol_path):
        print(f"Error: COBOL path '{cobol_path}' does not exist.")
        sys.exit(1)
    
    if output_path is None:
        output_path = os.path.join(os.getcwd(), "Cobol_Documentation_Output")
        print(f"No output path provided. Using default: '{output_path}'")
    
    if not os.path.exists(output_path):
        os.makedirs(output_path)
        print(f"Created output directory at '{output_path}'.")
    
    # Finally check if we can find the copilot command and run it
    if shutil.which("copilot") is None:
        print("Error: 'copilot' command not found. Please ensure Copilot is installed and in your PATH.")
        sys.exit(1)
    
    print("Validation steps completed successfully. Moving to documentation generation...")

    # PROCESS SINGLE FILE ELSE DIRECTORY
    if os.path.isfile(cobol_path):
        print("Processing single COBOL file...")
        process_cobol_file(cobol_path, prompt_path, output_path)
    else:
        # First, collect all COBOL files to get total count
        cobol_files = []
        for root, _, files in os.walk(cobol_path):
            for file in files:
                if file.lower().endswith(".cbl") or file.lower().endswith(".cob"):
                    cobol_file_path = os.path.join(root, file)
                    cobol_files.append(cobol_file_path)
        
        if not cobol_files:
            print(f"No COBOL files found in '{cobol_path}'.")
            return
        
        print(f"Found {len(cobol_files)} COBOL file(s) to process...")
        
        # Process files with progress bar
        for cobol_file_path in tqdm(cobol_files, desc="Processing COBOL files", unit="file"):
            process_cobol_file(cobol_file_path, prompt_path, output_path)
    print("Documentation generation completed.")


def process_cobol_file(cobol_file_path, prompt_path, output_path):
    # Get base filename for cleaner progress display
    file_name = os.path.basename(cobol_file_path)
    
    # Grab our prompts
    prompt_files = [file for file in os.listdir(prompt_path) if file.endswith(".txt")]
    
    if not prompt_files:
        print(f"No prompt files found in '{prompt_path}'. Skipping file.")
        return
    
    # Process each prompt file with progress bar
    for prompt_file in tqdm(prompt_files, desc=f"Processing {file_name}", unit="prompt", leave=False):
        prompt_file_path = os.path.join(prompt_path, prompt_file)
        with open(prompt_file_path, 'r') as pf:
            prompt_content = pf.read()
        
        final_prompt = f"{prompt_content}. Please generate documentation for the following COBOL code:{cobol_file_path}"
        # Construct the copilot command
        command = shutil.which("copilot")
        print(command)
        cmd = [command, "-p", final_prompt, "--allow-all-tools"]
        
        # Execute the command
        process = subprocess.Popen(cmd, stdout=PIPE, stderr=PIPE)
        stdout, stderr = process.communicate()

        # write the output to the output file
        output_file_name = f"{os.path.basename(cobol_file_path)}_{os.path.splitext(prompt_file)[0]}_documentation.txt"
        output_file_path = os.path.join(output_path, output_file_name)
        with open(output_file_path, 'wb') as out_file:
            out_file.write(stdout)
        
        if process.returncode != 0:
            tqdm.write(f"Error generating documentation for '{cobol_file_path}' with prompt '{prompt_file}': {stderr.decode()}")
        else:
            tqdm.write(f"Successfully generated documentation for '{file_name}' with prompt '{prompt_file}'.")

if __name__ == "__main__":
    main()

setup.py构建脚本

from setuptools import setup

setup(
    name="mts-gendoc-cobol",
    version="1.0.4",
    description="Generate COBOL documentation using Copilot",
    author="Ben Bastianelli",
    author_email="benbastianelli@gmail.com",
    packages=["gendoc"],
    entry_points={
        'console_scripts': [
            'gen-doc=gendoc.__main__:main'
        ]
    },
    classifiers=[
        "Programming Language :: Python :: 3",
        "Operating System :: OS Independent",
    ],
    python_requires='>=3.6',
)

打包部署命令

# 打包命令
python .\set_up.py sdist bdist_wheel
twine upload dist/*

# 安装步骤
pip install mts-gendoc-cobol

# 使用方式
gen-doc -p PROMPT_DIR -c COBOL_CONTEXT -o OUT

排查方向及解决建议

  1. 环境变量传递问题
    本地脚本继承当前Shell的环境变量,而pip包作为console_script运行时,环境变量可能受限。Copilot CLI可能依赖API密钥、配置路径等未正确传递的变量。

    • 解决:调用subprocess.Popen时添加env=os.environ.copy()参数,显式传递完整环境变量。
  2. 命令参数解析异常
    打包后,过长或含特殊字符的final_prompt可能导致Copilot CLI无法正确解析。本地运行时Shell会处理参数,但console_script的参数传递逻辑存在差异。

    • 解决:将prompt内容写入临时文件,通过文件路径传递给Copilot CLI(若支持);或对prompt内容做转义处理。
  3. 工作目录不一致
    打包后的命令运行时,工作目录可能不是用户当前目录,导致Copilot内部相对路径操作失败。

    • 解决:在subprocess.Popen中添加cwd=os.getcwd()参数,显式指定子进程工作目录。
  4. 错误信息未完整捕获
    即使进程返回码为0,Copilot CLI可能存在静默错误导致输出为空。当前代码仅在返回码非零时打印stderr,无法排查此类情况。

    • 解决:无论返回码如何,都打印完整的stderr内容;同时添加超时机制(如process.communicate(timeout=30)),避免进程提前退出或挂起。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 03:09:53