小能豆

如何使 python 包引用打包的非 python 可执行文件 (.exe);Windows

py

我正在组装一个使用 Cygwin 可执行文件的 Python 包,但无需安装 Cygwin。这意味着我的包中有一个可执行.exe文件 () 和一个库文件 ( .dll)。我这样做是为了让只使用 Windows 和 Python 的人可以在 Windows 上使用该工具。我是 Python 包的新手,因此非常感谢您的帮助。


主要问题

如何使我的包指向包内的可执行文件?例如,这将被用来代替 引用的可执行文件PATH。答案可能就在那里,但我在搜索中找到的只是一堆关于如何从 Python 脚本创建可执行文件的信息,这不是我想要的。


详细信息/我的尝试

该工具是sclite,一种对语音识别输出进行评分的工具。有关如何在 Windows 上使用该工具的信息,请参阅下面的如何安装 SCLITE(用于可复制性)部分。

这是一个关于我如何设置包裹的小“玩具”示例。

$ tree package_holder_dir/
package_holder_dir/
├── bbd_package
│   ├── __init__.py
│   ├── non_py_exe_dll
│   │   ├── cygwin1.dll
│   │   └── sclite.exe
│   ├── score
│   │   ├── __init__.py
│   │   └── run_sclite.py
│   └── score_transcript.py
├── MANIFEST.in
├── README.txt
└── setup.py

3 directories, 9 files

我的第一个猜测是它sclite.exe应该放在MANIFEST.in文件中。

# @file MANIFEST.in

include ./README.txt
include ./bbd_package/non_py_exe_dll/sclite.exe
include ./bbd_package/non_py_exe_dll/cygwin1.dll

我也尝试把它们放进去setup.py

我的setup.py如下

#!/usr/bin/env/python3
# -*- coding: utf-8 -*-
# @file setup.py

import setuptools
from distutils.core import setup

with open ("README.txt", "r") as fh:
  long_description = fh.read()

setup(
  name='bbd_package',
  url='user@host.com',
  author='bballdave025',
  author_email='not.likely@idontwantspam.com',
  packages=setuptools.find_packages(),
  #data_files=[('lib', ['./non_py_exe_dll/cygwin1.dll']),
  #                     './non_py_exe_dll/sclite.exe'],
  version='0.0.1',
  description="Example for SO",
  long_description=long_description,
  include_package_data=True
) ##endof:  setup

请注意,我使用这个源(已存档data_files)作为 的位置DLL。但是,当我在其他地方安装发行版时,我找不到这些文件。这就是为什么在这里将它们注释掉的原因。

使用似乎可行,但随后我必须使用相对路径来访问可执行文件。如果尝试在另一个目录中MANIFEST.in访问,则此方法无效。import bbd_package

让我尝试用我的两个 Python 文件来说明:

score_transcript.py只需调用run_sclite.py

#!/usr/env/bin python3
# -*- coding: utf-8 -*-
# @file run_sclite.py

import os, sys, subprocess

def run_sclite(hyp, ref):
  subprocess.call(['../non_py_exe_dll/sclite.exe', '-h', hyp, '-r', ref, '-i', 'rm', \
                   '-o', 'all snt'])

我可以将它安装在我的系统上:

C:\toy_executable_example\package_holder_dir>pip install .

然后如果我碰巧在目录中run_sclite.py

C:\toy_executable_example\package_holder_dir\bbd_package\score>python
Python 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 17:00:18) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import bbd_package.score.run_sclite
>>> bbd_package.score.run_sclite.run_sclite('a.hyp', 'a.ref')
sclite Version: 2.10, SCTK Version: 1.3
...output that shows it works...
>>>

然而,从任何其他目录来看,都没有结果。

C:\Users\me>python
Python 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 17:00:18) [MSC v.1900 64 bit 
(AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import bbd_package.score.run_sclite
>>> bbd_package.score.run_sclite.run_sclite('a.hyp', 'a.ref')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\dblack\AppData\Local\Programs\Python\Python36\lib\site-packages\bbd_package\score\run_sclite.py", line 9, in run_sclite
    '-o', 'all snt'])
  File "C:\Users\dblack\AppData\Local\Programs\Python\Python36\lib\subprocess.py", line 267, in call
    with Popen(*popenargs, **kwargs) as p:
  File "C:\Users\dblack\AppData\Local\Programs\Python\Python36\lib\subprocess.py", line 709, in __init__
    restore_signals, start_new_session)
  File "C:\Users\dblack\AppData\Local\Programs\Python\Python36\lib\subprocess.py", line 997, in _execute_child
    startupinfo)
FileNotFoundError: [WinError 2] The system cannot find the file specified
>>>

我怎样才能告诉 Python 在我的包中寻找可执行文件?


系统详细信息

此信息是systeminfo从 Windows 命令提示符运行中获取的。

OS Name:                   Microsoft Windows 10 Enterprise
OS Version:                10.0.15063 N/A Build 15063
OS Manufacturer:           Microsoft Corporation
OS Configuration:          Member Workstation
OS Build Type:             Multiprocessor Free

如何安装 SCLITE(为了可重复性)

我在这里附上了一个安装说明的链接(使用 Cygwin),请查看我的评论。以下是没有解释的命令

$ cd
$ git clone https://github.com/kaldi-asr/kaldi.git
$ cd kaldi/tools
$ extras/check_dependencies.sh
$ make -j $(nproc --all)
$ cp -R sctk-2.4.10 ~/
$ cd
$ rm -rf kaldi
$ cd sctk-2.4.10/
$ cp $HOME/.bashrc "${HOME}/.bashrc.$(date +%Y%m%d-%H%M%S).bak"
$ echo -e "\n\n## Allow access to sclite, rfilter, etc" >> $HOME/.bashrc
$ echo 'export PATH='"$(pwd)/bin"':$PATH' >> $HOME/.bashrc
$ source ~/.bashrc

我还附上了一个链接已存档EXE),其中包含“更快”的说明以及有关和文件的信息DLL。这一切都要感谢@benreaves

Easier (but even uglier) workaround, which I gave to an intern who did some Word Error Rate calculations for me:

On my laptop with Cygwin installed, I create sclite.exe using my

py cp src/*/*.c . ; make all

workaround from my previous message

I create a zip file containing sclite.exe and cygwin1.dll from my laptop’s c:/cygwin/bin/ folder

我没有设置PATH,因为我希望它是可分发的。

This worked just fine on her laptop running Windows 7, and she didn’t need Cygwin or any other NIST software on her laptop.

-Ben


阅读 14

收藏
2024-12-31

共1个答案

小能豆

我终于让它工作了。我拼凑起来的源代码如下。基本答案是我使用变量__file__来查找调用打包模块的目录,然后使用相对路径来获取我的可执行文件。我对这个解决方案并不满意(这里{ archived } 是一些它不起作用的情况),但它现在完成了工作。

具体内容

文件MANIFEST.in保持不变:

# @file MANIFEST.in
# @author bballdave025

include ./README.txt
include ./bbd_package/non_py_exe_dll/sclite.exe
include ./bbd_package/non_py_exe_dll/cygwin1.dll

但是,我需要将以下内容添加到exe运行代码中。这是run_sclite.py

from pathlib import Path
#...
path_to_here = os.path.dirname(os.path.abspath(__file__))
path_to_pkg_root = Path(path_to_here).resolve().parents[1]
path_to_exe = os.path.join(path_to_pkg_root, 'non_py_exe_dll')
#...

请注意,Python 版本 >= 3.4 是必需的pathlib

以下是整个 ( run_sclite.py) 文件:

#!/usr/env/bin python3
# -*- coding: utf-8 -*-
# @file run_sclite.py
# @author bballdave025

import os, sys, subprocess
from pathlib import Path

def run_sclite(hyp, ref):
  path_to_here = os.path.dirname(os.path.abspath(__file__))
  path_to_pkg_root = Path(path_to_here).resolve().parents[1]
  path_to_exe = os.path.join(path_to_pkg_root, 'non_py_exe_dll')

  subprocess.call([os.path.join(path_to_exe, 'sclite.exe'), '-h', hyp, '-r', ref, \
                   '-i', 'rm', '-o', 'all snt'])

##endof:  run_sclite(hyp, ref)
2024-12-31