【问题标题】:Finding a file in a Python module distribution [duplicate]在 Python 模块分发中查找文件 [重复]
【发布时间】:2010-09-07 12:50:38
【问题描述】:

我编写了一个 Python 包,其中包含一个 bsddb 数据库,其中包含一个用于更耗时的计算的预计算值。为简单起见,我的安装脚本将数据库文件安装在与访问数据库的代码相同的目录中(在 Unix 上,类似于 /usr/lib/python2.5/site-packages/mypackage/)。

如何存储数据库文件的最终位置,以便我的代码可以访问它?现在,我正在使用基于访问数据库的模块中的__file__ 变量的hack:

dbname = os.path.join(os.path.dirname(__file__), "database.dat")

它有效,但它似乎...... hackish。有一个更好的方法吗?我想让安装脚本从 distutils 模块中获取最终安装位置,并将其填充到“dbconfig.py”文件中,该文件与访问数据库的代码一起安装。

【问题讨论】:

标签: python distutils


【解决方案1】:

尝试使用 pkg_resources,它是 setuptools 的一部分(在我现在可以访问的所有 python 上都可用):

>>> import pkg_resources
>>> pkg_resources.resource_filename(__name__, "foo.config")
'foo.config'
>>> pkg_resources.resource_filename('tempfile', "foo.config")
'/usr/lib/python2.4/foo.config'

eggs 页面和pkg_resources 页面上有更多关于使用 pkg_resources 获取资源的讨论。

另外请注意,可能建议使用 pkg_resources.resource_stream 或 pkg_resources.resource_string,因为如果包是鸡蛋的一部分,resource_filename 会将文件复制到临时目录。

【讨论】:

  • 这会让你的包依赖于setuptools,这在标准库中是不存在的。
  • @techtonik 遗憾的是,访问资源的两种标准方法是使用 disutils 或 setuptools。仅使用标准库来访问模块中的资源并没有像样的方法。这部分是因为如果没有外部库,很难构建一个可广泛分发的模块。
  • 这是正确的答案,因为 setuptools 是部分 pip 并且最近的 Python 有 ensure_pip。
  • 不再。从 Python-3.7 开始,标准方法是使用 importlib.resources 标准库的模块。
【解决方案2】:

使用pkgutil.get_data。它是pkg_resources.resource_stream 的表亲,但在标准库中,应该与平面文件系统安装以及压缩包和其他导入器一起使用。

【讨论】:

  • 比起使用 pkg_resources,我更喜欢这个,因为 pkgutil 总是可用的,而且因为 pkg_resources 似乎会触发解压 $PYTHON_EGG_CACHE 目录中的压缩鸡蛋,这违背了使用压缩鸡蛋的目的。 .
【解决方案3】:

这可能就是这样做的方法,而无需求助于更高级的东西,例如使用 setuptools 将文件安装到它们所属的位置。

请注意,这种方法存在问题,因为在具有真正安全框架(UNIX 等)的操作系统上,运行脚本的用户可能无权访问安装它的系统目录中的数据库。

【讨论】:

    【解决方案4】:

    使用标准 Python-3.7 库的importlib.resources module, 这是more efficient 而不是setuptools:pkg_resources (在以前的 Python 版本中,使用向后移植的 importlib_resources library)。

    注意:为此,数据文件所在的文件夹必须是常规的 python 包。这意味着您必须将__init__.py 文件添加到其中,如果还没有的话。

    然后你可以这样访问它:

    try:
      import importlib.resources as importlib_resources
    except ImportError:
      # In PY<3.7 fall-back to backported `importlib_resources`.
      import importlib_resources
    
    
    ## Note that the actual package could have been used, 
    #  not just its (string) name, with something like: 
    #      from XXX import YYY as data_pkg
    data_pkg = '.'
    fname = 'database.dat'
    
    db_bytes = importlib_resources.read_binary(data_pkg, fname)
    # or if a file-like stream is needed:
    with importlib_resources.open_binary(data_pkg, fname) as db_file:
        ...
    

    【讨论】:

      猜你喜欢
      • 2022-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-20
      • 1970-01-01
      • 2012-07-02
      • 1970-01-01
      相关资源
      最近更新 更多