设置 Python 项目以通过 Homebrew 进行打包和分发

问题描述 投票:0回答:1

我正在尝试为 Python 项目创建一个 Homebrew 公式。

这是自制公式:

class Scanman < Formula
  include Language::Python::Virtualenv

  desc "Using LLMs to interact with man pages"
  url "https://github.com/nikhilkmr300/scanman/archive/refs/tags/1.0.1.tar.gz"
  sha256 "93658e02082e9045b8a49628e7eec2e9463cb72b0e0e9f5040ff5d69f0ba06c8"

  depends_on "[email protected]"

  def install
    virtualenv_install_with_resources
    bin.install "scanman"
  end

  test do
    # Simply run the program
    system "#{bin}/scanman"
  end
end

使用安装的 scanman 版本运行应用程序时,无法找到 src 目录中的自定义模块。

ModuleNotFoundError: No module named 'src'

对于为什么会发生这种情况有任何见解吗?

这是我的目录结构(如果有帮助的话):

.
├── requirements.txt
├── scanman
├── scanman.rb
├── setup.py
└── src
    ├── __init__.py
    ├── cli.py
    ├── commands.py
    ├── manpage.py
    ├── rag.py
    └── state.py

主要可执行文件是

scanman
。这是一个 Python 脚本,可让您使用 LLM 与手册页进行交互。

值得注意的是:

  • 当我从我的存储库运行本地版本的
    scanman
    时,它工作得非常好。
  • 从 PyPI 安装的其他第 3 方软件包不会引发任何错误。然而,我在
    /usr/local/Cellar/scanman/1.0.1/libexec/lib/python3.11/site-packages/
    中找不到它们。
python homebrew python-packaging
1个回答
1
投票

我查看了 repo,发现

scanman
本身就是一个 Python 脚本。

你实际上有两个问题:

  1. 您在
    packages=find_packages(where="src")
    中设置
    setup.py
    ,这会告诉 Setuptools(读取
    setup.py
    并构建软件包的程序)安装 src
     内的所有内容。因此,您的模块 
    cli.py
    commands.py
     等最终都会安装为顶级模块,您可以通过 
    import cli
    import commands
     进行访问。这可能不是你想要的。
  2. 正如评论中所讨论的,你的 shebang
  3. #!/usr/bin/env python3
     受到 
    PATH
     中任何内容的支配,它甚至可能不受 Homebrew 管理,更不用说 Homebrew 为你的包创建的特定 venv 了。
我在评论中详细阐述了一些更多的打包问题和可能的简单解决方案。如果您正在使用法学硕士来完成这项工作,请使用其他的,因为它会给您提供不好的建议。你

不应该制作一个名为src

的可Pip安装包。你
应该努力做到这一点,以便Python可以找到你的代码,而无需任何额外的环境变量或其他混乱。您也不想重写您的代码。我在这里的建议是为了实现所有这些目标。

看起来您已经在尝试制作一个可安装 Pip 的软件包,所以我不会胡乱尝试让您当前的设置正常工作,而是将说明如何以一种不会造成混乱并遵循标准的方式来做到这一点长期存在的约定。

您的文件结构将如下所示:

./ Formula/ scanman.rb .gitignore requirements.txt setup.py src/ scanman/ __init__.py __main__.py cli.py commands.py manpage.py rag.py state.py
缺少顶级 

scanman

 脚本是故意的。继续阅读。

你的

setup.py

 变成:

from setuptools import setup, find_packages setup( name="scanman", description="Using LLMs to interact with man pages", url="https://github.com/nikhilkmr300/scanman", author="Nikhil Kumar", author_email="[email protected]", license="MIT", packages=find_packages(where="src"), install_requires=[ "faiss-cpu", "langchain", "langchain-openai", "langchainhub", "openai", "termcolor" ], entry_points={ "console_scripts": [ "scanman = scanman.__main__:main", ] }, )
请注意,这与您之前的内容

几乎相同。

然后:

    将所有带有
  1. src.cli
    src.manpage
     等的导入更改为 
    scanman.cli
    scanman.manpage
  2. scanman
     脚本的内容移至脚本 
    src/scanman/__main__.py 内的 function
    ,然后删除 shebang 行。
    。在您的开发环境(最好是 venv!)中运行 
    pip install --editable .
    。只需运行一次,更新代码时无需重新运行。
您生成的

src/scanman/__main__.py

脚本将如下所示:

import argparse import logging import os import readline import sys from langchain.memory import ConversationBufferWindowMemory from termcolor import colored from scanman.cli import prompt from scanman.commands import Command from scanman.manpage import Manpage from scanman.rag import ERROR_MSG, ask, load_retriever from scanman.state import State def main(): logger = logging.getLogger(__name__) logging.basicConfig(level=logging.ERROR) ... # all the stuff that was under the if-name-main block if __name__ == "__main__": main()
请注意,您不需要同时使用 

logging.basicConfig(level=logging.ERROR)

logger.setLevel(logging.ERROR)
。日志级别是分层的;无论您在根记录器上设置什么(这就是 
logging.basicConfig(level=...)
 所做的),都将传播到所有其他记录器,除非您在其他记录器上明确设置不同的级别。

作为测试,您应该能够使用开发者环境运行

python -m scanman

scanman

# Create a fresh venv and install into it: /opt/homebrew/bin/python3 -m venv ./venv-testing ./venv-testing/bin/pip install -r requirements.txt . # Both should now work: ./venv-testing/bin/scanman ./venv-testing/bin/python -m scanman
我们喜欢 

src/

 布局的原因是从 Python 搜索路径中隐藏你的源代码,这样你就 100% 确定你只运行安装在 venv 中的代码版本,
无论如何当您运行代码时,您的 Git 存储库中恰好有该文件。这提高了您的代码在其他人的机器上运行的机会。

最后,我建议将 Homebrew 公式移至

Formula/

 目录,因为这是 Homebrew 中的标准,并且它清楚地表明 
scanman.rb
 是 Homebrew 公式,而不是另一个项目脚本。


在你的仓库中,我还想指出你做的一些

正确的事情!

首先,您只在主脚本中设置日志配置,而不是在库代码中设置。这很好,因为您不应该尝试从库代码内部修改全局应用程序状态。

看起来您正在使用

pip-compile

pip freeze
 来发出 
requirements.txt
。这是一个
伟大的主意。继续这样做!遗憾的是,我不知道如何让 Homebrew 实际安装该文件中的依赖项,而不是仅使用 setup.py
 中声明的包 deps 并进行完整的依赖项解析。您可能需要在 Homebrew 论坛中询问。理想情况下,Homebrew 会运行这样的东西:

$VENV_DIR/bin/pip install -r requirements.txt ./
但这需要它在安装之前克隆您的存储库,而不是简单地通过 Pip 从 Github 直接安装。

© www.soinside.com 2019 - 2024. All rights reserved.