我想在PyPI上发布一个python软件包,该软件包具有调用可执行文件的类的方法。
该软件包的结构如下:
/project
LICENSE
MANIFEST.in
README.md
setup.py
/package_name
classA.py
classB.py
executableFile
classC.py
在classA.py方法中,我使用subprocess
模块调用可执行文件,如下所示:
subprocess.call('./executableFile', shell=True)
如果我通过pip
在virtualenv中安装了软件包,并且使用安装的软件包获得了main.py脚本,如下所示:
from package.classA import classA
obj_instance = classA()
obj_instance.method() #inside this method there is the subprocess.call(...)
程序崩溃,并告诉我未找到可执行文件。我认为是因为subprocess.call(...)
在存在main.py而不是package文件夹的文件夹中搜索了executeFile。
如何指定可执行文件的确切路径?
我尝试使用
os.path.dirname(os.path.abspath('executableFile'))
获取包文件夹的名称,但它会向我返回存在main.py的文件夹路径
我该如何解决?
谢谢。
答案 0 :(得分:0)
setuptools
带有pkg_resources
框架,用于处理此类情况。
那里有很多文章可供阅读,我不知道有什么好的教程,但是基本思路是:
您将executableFile
指定为文件资源。 setuptools
找出在安装(或车轮组装)时将其粘贴在哪里。
在运行时,您调用resource_filename
以获取到executableFile
的路径,然后subprocess.call
该路径。
您可能还想使用atexit
cleanup_resources
函数。
在幕后,pkg_resources
将找出所有详细信息。使用--inplace
,它将成为您源代码树中的文件;展开安装后,它将是您site-packages
中某个位置的文件;如果安装了egg,或者作为py2exe
等压缩的站点包的一部分,它将是根据需要提取到缓存目录的文件。但是您不必为此担心。您只需找到一条路径即可。
同时:
我认为发生这种情况是因为
subprocess.call(...)
在main.py文件夹而不是package文件夹中搜索了executableFile。
它搜索当前的工作目录。该可能与目录main.py
所在的目录相同,但前提是您的用户通过更改到该目录并运行./main.py
或python main.py
或相似。
我尝试使用
os.path.dirname(os.path.abspath('executableFile'))
那是行不通的,因为abspath
也在搜索当前的工作目录,因此,这是获得相同错误路径的更复杂的方法。然后您dirname
,然后返回无用的工作目录。
如果您知道从package.classA.py
到executableFile
的相对路径,则可以通过以下方式找到它:
packagedir = os.path.dirname(os.path.abspath(__file__))
execdir = os.path.join(packagedir, '<that relative path>')
execpath = os.path.join(execdir, 'executableFile')
或者,如果您知道来自main.py
的相对路径,则可以在main.py
内执行相同的操作,并将该路径存储在以后使用的位置(例如,将其传递到{{1} }构造函数。
但这不是理想的解决方案。源树中的相对路径可能与安装后的相对路径不同。如果您的用户以鸡蛋的形式安装软件包,或者将软件包与其他应用程序库的其余部分捆绑在一个zip文件中,那么您只是获得了鸡蛋或zip的路径,因此没有classA
可以找到相对于此的任何地方,因为它仅存在于存档中。依此类推。
executableFile
的要点是解决所有这些问题,也许是我没有想到的其他问题,以及可能在Python 3.7 / pip 10 / setuptools 40中不存在但将在以下版本中存在的其他问题:您的一位用户从现在起18个月后就开始使用它的Python 3.8 / pip 12 / setuptools 45早就忘记了如何使它一切正常运行...