无法在 BitBucket 上使用 pythonnet 加载特定包

Failing to load specific packages with pythonnet on BitBucket

提问人:Denise Skidmore 提问时间:8/17/2023 最后编辑:Denise Skidmore 更新时间:8/18/2023 访问量:40

问:

我正在使用 pythonnet 从 Python 调用 .NET dll。我的代码都可以在我的本地机器上运行,但是当我在 BitBucket 服务器上进行单元测试时,它失败了。

首先,我有一个步骤,用于构建一个虚拟的 .NET 6 exe,以触发 nuget 包的下载。这将运行并创建一个项目,以便在下一步中使用。image: mcr.microsoft.com/dotnet/sdk:6.0

然后我在镜像上设置了pythonnet环境:image: python:3.11

        - if [ -f unit_test_requirements.txt ]; then pip install -r unit_test_requirements.txt; fi
        - export PYTHONPATH=$PYTHONPATH:$BITBUCKET_CLONE_DIR/ctop:$ARCHIVE
        # Pure python tests that run fine here...
        - wget https://dot.net/v1/dotnet-install.sh -O dotnet-install.sh
        - chmod +x ./dotnet-install.sh
        - ./dotnet-install.sh --runtime dotnet --version latest
        - export DOTNET_ROOT=$HOME/.dotnet
        - export PATH=$PATH:$DOTNET_ROOT:$DOTNET_ROOT/tools
        - export PYTHONPATH=$PYTHONPATH:$DOTNET_ROOT:$DOTNET_ROOT/tools

pythonnet 3.0.1 安装

Collecting pythonnet (from -r unit_test_requirements.txt (line 3))
  Using cached pythonnet-3.0.1-py3-none-any.whl (284 kB)

python -c "import sys; print(sys.path)"打印所需的文件夹。

我在单元测试中得到的错误深深地埋藏在导入树中,所以我进行了简化。我可以加载我自己的 Dll,它依赖于 System.Text.Json 2 级深度。我可以从 System 命名空间加载类。System.Text.Json 存在于我的存档文件夹中,但是当我尝试加载 System.Text.Json 时,出现错误。我的解决方案中的 System.Text.Json 是 7.0.3,文件夹中的文件版本显示 7.0.723.27404,但 ILSpy 报告版本 (7.0.0.0) 和令牌与错误消息匹配。

+ python -c "from pathlib import Path;print(Path('.../My.A.dll').exists())"
True

+ python -c "from pythonnet import load;load('coreclr');import clr;clr.AddReference('My.A');from My.A.Namespace import B"

+ python -c "from pythonnet import load;load('coreclr');import clr;from System import Guid, String, Action"

+ python -c "from pathlib import Path;print(Path('.../System.Text.Json.dll').exists())"
True

+ python -c "from pythonnet import load;load('coreclr');import clr;clr.AddReference('System.Text.Json');import clr;from System.Text.Json import JsonConverter"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
System.IO.FileLoadException: Could not load file or assembly 'System.Text.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.

我将工件下载到我的本地 PC,将我的本地 pythonpath 更改为指向那里,所有这些命令在我的本地 PC 上都能正常通过,并且在本地进行了相当强大的单元测试。所以它不是神器本身。(是的,在我更改 env 变量后启动的新控制台窗口中。

我不认为这是.NET版本的问题。 我使用的是pythonnet 3.0.1,所以PythonNet 2.x不支持核心不是问题。System.Json.Text 7.0.3 支持 .NET 6、.NET Standard 2.0 和 .NET Framework 4.6.2,因此在任何情况下都应加载。我正在执行加载核心的所有步骤。我正在我的步骤中安装 .NET 6:

+ ./dotnet-install.sh --runtime dotnet --version latest
...
dotnet-install: Installed version is 6.0.21
...
dotnet-install: Installation finished successfully.

我有第二个 Windows 环境也遇到类似的错误,但我无法直接访问它,所以我首先处理 CI/Bitbucket 环境,希望这是一个常见的根本问题。

Bitbucket python.net 程序集加载

评论

0赞 Denise Skidmore 8/17/2023
建议将 $DOTNET_ROOT/tools 添加到某处的路径中,但我认为该文件夹实际上并不存在。稍微挖掘一下,没有在 .dotnet 根目录中发现任何名为 tools 的文件夹。
0赞 Denise Skidmore 8/17/2023
可能相关问题:github.com/pythonnet/pythonnet/discussions/2217
0赞 Denise Skidmore 8/17/2023
同一问题的早期迭代,具有较少的装配负载调查,但尝试了更多的映像设置。github.com/pythonnet/pythonnet/discussions/2194

答:

0赞 Denise Skidmore 8/17/2023 #1

我的运行时版本错误。System.Text.Json 7.0 说它与 .NET 6 兼容,但我的问题在安装 .NET 7 时消失了。我还更改了安装方法,但我用新的安装方法和 .net 6 进行了测试,它也失败了。

修复过程:

一条警告消息向我发送了特定于操作系统的安装路径。

dotnet-install: Note that the script does not resolve dependencies during installation.
dotnet-install: To check the list of dependencies, go to https://learn.microsoft.com/dotnet/core/install, select your operating system and check the "Dependencies" section.

安装说明需要特定的 linux 发行版,所以我得到了:

+ cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"

然后使用特定于操作系统的安装说明 https://learn.microsoft.com/en-us/dotnet/core/install/linux-debian#debian-12(针对最小安装和 bitbucket 环境略有修改)

        - wget https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
        - dpkg -i packages-microsoft-prod.deb
        - rm packages-microsoft-prod.deb
        - apt-get update && apt-get install -y dotnet-runtime-7.0

这使得 dotnet root 移动(如图所示),所以我不得不更新dotnet --list-runtimesexport DOTNET_ROOT=/usr/share/dotnet/

1赞 LOST 8/18/2023 #2

您可能需要传递参数来告知 .NET 如何查找包依赖项。例如 .runtimeconfigload("coreclr", runtimeconfig="path.runtimeconfig")

.NET 7 可能适合你,因为所有 System.Json.Text 7.0 依赖项都与它捆绑在一起。

查看 https://github.com/pythonnet/pythonnet/blob/3b6500fbdc844096665a24ba07f5a56c11192e1b/doc/source/python.rst#calling-pythonnetload

评论

0赞 Denise Skidmore 8/18/2023
我们团队的其他部分正在迁移到 .NET 7,因此这对我来说是一个可以接受的解决方案。我的另一个选择是将我的依赖树整理回版本 6.* 包。
0赞 Denise Skidmore 8/18/2023
我下载nugets的项目确实生成了一个runtimeconfig.json,因此生成一个不会有很多手工工作,但是我会遇到相对于我的脚本查找运行时配置的新问题,这在所有环境中都不相同。无论如何,目标环境都需要安装运行时,将它们指向解决所有问题的运行时会很有帮助。
0赞 Denise Skidmore 8/18/2023
我可以将一个本地工作runtimeconfig.json复制到脚本中,但我希望它只与它在生产中获取 dll 的应用程序一起使用,并且我们使用 pythonpath 设置。