如何使python包引用已打包的非python可执行文件(.exe);视窗 [英] How to make python package refer to packaged, non-python executable (.exe); Windows

查看:119
本文介绍了如何使python包引用已打包的非python可执行文件(.exe);视窗的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在整理一个使用Cygwin可执行文件的Python程序包,而未安装Cygwin.这意味着我的程序包中有一个可执行文件(.exe)和一个库文件(.dll).我这样做是为了让只有Windows和Python的人才能在Windows上使用该工具.我是Python包的新手,所以感谢您的帮助.

I am putting together a Python package that uses a Cygwin executable without having Cygwin installed. This means that I have an executable (.exe) file and a library (.dll) file inside my package. I am doing this so that the tool can be used on Windows by people who only use Windows and Python. I am new to Python packages, so I appreciate any help.

如何使程序包指向程序包中的可执行文件?例如,将使用它代替PATH引用的可执行文件.答案可能在那里,但是我在搜索中发现的只是关于如何从Python脚本创建可执行文件的一堆信息,这不是我想要的.

How do I make my package point to the executable file inside my package? This would be used, for example, instead of the executable referenced by PATH. The answer might be out there, but all I've found in my search is a bunch of info on how to create an executable from a Python script, which is NOT what I want.

该工具是sclite,这是对语音识别输出进行评分的工具.有关如何在Windows上获得该工具的信息,请参阅下面的如何安装SCLITE(用于再现性)部分.

The tool is sclite, a tool to score speech recognition output. For information about how I get the tool available on Windows, have a look at the How to Install SCLITE (for reproduce-ability) section, below.

这是我如何设置包裹的小型玩具"示例.

Here's a small, "toy" example of how I have my package set up.

$ 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文件中.

My first guess was that the sclite.exe should go in the MANIFEST.in file.

# @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的位置.但是,在其他地方安装发行版时找不到文件.这就是为什么在这里将它们注释掉.

Note this source for my use of data_files for the location of the DLL. However, I could not find the files when I installed the distribution elsewhere. That's why they are commented out here.

使用MANIFEST.in似乎可行,但是随后我不得不使用相对路径来访问可执行文件.尝试在另一个目录中import bbd_package时,这将不起作用.

Using MANIFEST.in seemed to work, but then I had to use a relative path to access the executable. That won't work when trying to import bbd_package in another directory.

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

Let me try to illustrate with my two Python files:

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'])

我可以在系统上安装它:

I can install it on my system:

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...
>>>

但是,在任何其他目录中,都没有骰子.

However, from any other directory, no dice.

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在包中查找可执行文件?

How can I tell Python to look for the executable inside my package?

此信息来自在Windows的命令提示符下运行systeminfo.

This information is taken from running systeminfo from Window's Command Prompt.

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),以查找我的评论.这是没有解释的命令


How to Install SCLITE (for reproduce-ability)

I'm including a link to the installation instructions (using Cygwin) here, look for my comment. Here are the commands with no explanation

$ 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

I'm also including a link to "quicker" instructions and the information about the EXE and DLL files. This is all thanks to @benreaves

更简单(但更难看)的解决方法,我将其提供给了一名实习生, 一些针对我的字词错误率计算:

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

在装有Cygwin的笔记本电脑上,使用

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

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

我上一封邮件中的解决方法

workaround from my previous message

我从我的目录中创建一个包含sclite.execygwin1.dll的zip文件 笔记本电脑的c:/cygwin/bin/文件夹

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

将该压缩文件发送给她,然后她将两个文件复制到一个新文件中 她的笔记本电脑set PATH=.;%PATH%

Email that zip file to her, and she copies both files in a single new folder on her laptop and set PATH=.;%PATH%

我不设置PATH,因为我希望它是可分发的.

I don't set the PATH, because I want this to be distributible.

这在运行Windows 7的笔记本电脑上工作得很好,但她没有 在她的笔记本电脑上需要Cygwin或任何其他NIST软件.

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

-本

推荐答案

我终于可以使用它了.下面是我修补的源.基本答案是,我使用了__file__变量来查找调用打包模块的目录,然后使用相对路径来获取我的可执行文件.我对这个解决方案并不真正满意(

I finally got this to work. The sources which I patched together are below. The basic answer is that I used the __file__ variable to find the directory from which the packaged module was called, then used relative paths to get to my executable. I'm not really satisfied with this solution (here are some situations in which it won't work), but it gets the job done for now.

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

However, I needed to add the following to the exe-running code. This is in 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')
#...

请注意,对于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)


来源

鼠标与Python的对比,并阐明了该解决方案何时不起作用以及其他替代方案.


Sources

Mouse vs. Python, with clarification on when this solution won't work and other alternatives.

获取包根目录(SO)

最终使我得到答案的是:

What finally got me to the answer: Python Packaging Tutorial . Look at the 'Note:'.

这篇关于如何使python包引用已打包的非python可执行文件(.exe);视窗的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆