在Python中以编程方式确定distutils数据文件的位置 [英] Determining the location of distutils data files programmatically in Python

查看:100
本文介绍了在Python中以编程方式确定distutils数据文件的位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将distutils中的数据文件包含在我的软件包中,然后使用相对路径来引用它们(以下

I'm trying to include data files in distutils for my package and then refer to them using relative paths (following http://docs.python.org/distutils/setupscript.html#distutils-additional-files)

我的目录结构是:

myproject/
  mycode.py
  data/
    file1.dat

mycode.py中的代码,它实际上是程序包中的脚本.它依赖于访问data/file1.dat,并使用该相对路径对其进行引用.在setup.py中,我有:

the code in mycode.py, which is actually a script in the package. It relies on accessing data/file1.dat, refer to it using that relative path. In setup.py, I have:

setup(
 ...
 scripts = "myproject/mycode.py"
 data_files = [('data', 'myproject/data/file1.dat')]
)

假设用户现在使用:

python setup.py --prefix=/home/user/

然后mycode.py将出现在/home/user/bin/之类的位置.但是对data/file1.dat的引用现在已被破坏,因为脚本位于数据的其他位置.

Then mycode.py will appear in some place like /home/user/bin/. But the reference to data/file1.dat is now broken, since the script lives elsewhere from the data.

如何从mycode.py中找出myproject/data/file1.dat的绝对路径,因此我可以根据用户在哪里安装软件包来正确引用它?

How can I find out, from mycode.py, the absolute path to myproject/data/file1.dat, so I can refer to it properly depending on where the user installed the package?

编辑
当我用prefix=/home/user/安装此文件时,得到的正是/home/user/中创建的data/file1.dat,这正是我想要的,唯一缺少的部分是如何以编程方式检索到该文件的绝对路径,仅给出了相对路径并且不知道用户安装软件包的位置.当我尝试使用package_data而不是data_files时,它不起作用-即使删除了MANIFEST文件,我也没有在任何地方创建data/file1.dat.

EDIT
When I install this with prefix=/home/user/, I get data/file1.dat created in /home/user/ which is exactly what I want, the only missing piece is how to retrieve the absolute path to this file programmatically, given only a relative path and not knowing where the user installed the package. When I try to use package_data instead of data_files, it does not work - I simply don't get data/file1.dat created anywhere, even if I delete my MANIFEST file.

我已经阅读了所有有关此表面上非常常见问题的当前讨论.但是,所有提议的解决方案都无法解决我上面提到的情况,其中需要访问data_files的代码是脚本,并且其位置可能会根据--prefix自变量setup.py.我唯一想到解决此问题的方法是将数据文件添加到setup()中的scripts=中,如下所示:

I've read all the of the current discussions of this apparently very common problem. All the proposed solutions however are not dealing with the case I have a above, where the code that needs to access data_files is a script and its location might change depending on the --prefix argument to setup.py. The only hack I can think of to resolve this is to add the data file to scripts= in setup(), as in:

setup(
  ...
  scripts = ["myproject/mycode.py", "myproject/data/file1.data"]
)

这是一个可怕的骇客,但这是我能想到的唯一确保file1.datascripts=中定义的脚本位于同一位置的方法,因为我找不到任何独立于平台且对安装敏感的API在用户运行setup.py install(可能带有--prefix= args)后恢复data_files的位置.

this is a horrible hack but it is the only way I can think of to ensure that file1.data will be in the same place as the scripts defined in scripts=, since I cannot find any platform independent and installation sensitive API to recover the location of data_files after the user ran setup.py install (potentially with --prefix= args).

推荐答案

我认为混淆是由脚本的使用引起的.脚本应引用可运行的可执行文件,可能是与您的软件包相关的实用程序脚本,也可能是指向软件包功能的入口点.无论哪种情况,您都应该期望所有脚本不会与软件包的其余部分一起安装.这种期望主要是由于以下约定:将软件包视为库(并安装到lib目录),而将脚本视为可执行文件(并安装到bin或Scripts目录).此外,数据文件既不是可执行文件也不是库,并且是完全独立的.

I think the confusion arises from the usage of scripts. Scripts should refer to a runnable executable, perhaps a utility script related to your package or perhaps an entry point into functionality for your package. In either case, you should expect that any scripts will not be installed alongside the rest of your package. This expectation is due mainly to the convention that packages are considered libraries (and installed to lib directories) whereas scripts are considered executables (and installed to bin or Scripts directories). Furthermore, data files are neither executables nor libraries and are completely separate.

因此,从脚本中,您需要确定数据文件的位置.根据 Python文档

So from the script, you need to determine where the data files are located. According to the Python docs,

如果目录是相对路径,则相对于目录解释 安装前缀.

If directory is a relative path, it is interpreted relative to the installation prefix.

因此,您应该在mycode脚本中编写类似以下内容的代码以找到数据文件:

Therefore, you should write something like the following in the mycode script to locate the data file:

import sys
import os

def my_func():
    with open(os.path.join(sys.prefix, 'data', 'file1.dat')) as f:
        print(next(f))

if __name__ == '__main__':
    my_func()

如果您对代码和数据没有捆绑在一起的方式不满意(我也不会),那么我将重组您的软件包,以便您拥有一个实际的Python软件包(和模块)并使用这些软件包=和package_data =将数据注入到程序包中,然后创建一个简单的脚本来调用程序包中的模块.

If you're not pleased with the way that your code and data are not bundled together (and I would not be), then I would restructure your package so that you have an actual Python package (and module) and use packages= and package_data= to inject the data into the package, and then create a simple script that calls into the module in the package.

我是通过创建此树来做到这一点的:

I did that by creating this tree:

.
│   setup.py
│
├───myproject
│   │   mycode.py
│   │   __init__.py
│   │
│   └───data
│           file1.dat
│
└───scripts
        run-my-code.py

使用setup.py:

With setup.py:

from distutils.core import setup

setup(
    name='myproject',
    version='1.0',
    scripts=['scripts/run-my-code.py'],
    packages=['myproject'],
    package_data = {
        'myproject': ['data/file1.dat'],
    },
)

run-my-code.py很简单:

run-my-code.py is simply:

from myproject import mycode

mycode.my_func()

__init__为空,mycode.py如下:

__init__ is empty and mycode.py looks like:

import os

here = os.path.dirname(__file__)

def my_func():
    with open(os.path.join(here, 'data', 'file1.dat')) as f:
        print(next(f))

后一种方法将数据和代码捆绑在一起(在site-packages/myproject中),并且仅将脚本安装在其他位置(因此它显示在$ PATH中).

This latter approach keeps the data and code bundled together (in site-packages/myproject) and only installs the script in a different location (so it shows up in the $PATH).

这篇关于在Python中以编程方式确定distutils数据文件的位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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