问题 如何从python控制台中访问python包元数据?


如果我已经构建了一个python包使用 distutils.core,例如通过

setup(
    ext_package="foo",
    author="me",
    version="1.0",
    description="foo package",
    packages=["foo",],
)

所有元数据在哪里(它的目的是什么?)以及如何从python中访问它。具体来说,如何在执行类似操作后从python控制台访问作者信息

>>> import foo

13009
2017-12-19 13:32


起源



答案:


访问元数据的一种方法是使用

import pip

package = [pckg for pckg in pip.get_installed_distributions() 
            if pckg.project_name == 'package_name'][0]
#  package var will contain some metadata: version, project_name and others.

要么 pkg_resources

from pkg_resources import get_distribution

pkg = get_distribution('package_name')  # also contains a metadata

5
2017-12-19 13:47



不幸的是我没有 pip 现在安装,所以无法测试。该 pkg_resources.get_distribution 对于通过简单安装的扩展,方法似乎不起作用 python setup.py build。在这种情况下,我得到一个 DistributionNotFound: foo 例外。 - dastrobu
python setup.py build没有安装。 - Éric Araujo
用于 pip 在导入时增加了巨大的延迟,并为您自己的代码增加了大量的内存占用。它内部只是使用 pkg_resources 并给你一个相同的结果;基本上, pip 这是无关紧要的,也是一种误导性的“解决方案”。答案实际上并没有获得所需的信息;从一个 Distribution 对象如何在其他领域中获取版本,作者和描述是非常不明显的。 pkg._get_metadata(pkg.PKG_INFO) 为初学者提供元数据文件中的各行作为列表。 - amcgregor


答案:


访问元数据的一种方法是使用

import pip

package = [pckg for pckg in pip.get_installed_distributions() 
            if pckg.project_name == 'package_name'][0]
#  package var will contain some metadata: version, project_name and others.

要么 pkg_resources

from pkg_resources import get_distribution

pkg = get_distribution('package_name')  # also contains a metadata

5
2017-12-19 13:47



不幸的是我没有 pip 现在安装,所以无法测试。该 pkg_resources.get_distribution 对于通过简单安装的扩展,方法似乎不起作用 python setup.py build。在这种情况下,我得到一个 DistributionNotFound: foo 例外。 - dastrobu
python setup.py build没有安装。 - Éric Araujo
用于 pip 在导入时增加了巨大的延迟,并为您自己的代码增加了大量的内存占用。它内部只是使用 pkg_resources 并给你一个相同的结果;基本上, pip 这是无关紧要的,也是一种误导性的“解决方案”。答案实际上并没有获得所需的信息;从一个 Distribution 对象如何在其他领域中获取版本,作者和描述是非常不明显的。 pkg._get_metadata(pkg.PKG_INFO) 为初学者提供元数据文件中的各行作为列表。 - amcgregor


元数据存储在 <package>-<version>-<py version>.egg-info 文件。

在创建模块时,您应该有这一行:

Writing /usr/lib/python2.7/site-packages/foobar-1.0-py2.7.egg-info

该文件包含元数据:

Metadata-Version: 1.0
Name: Foobar
Version: 1.0
Summary: foobar
Home-page: http://foobar.com/
Author: foobar
Author-email: foobar@foobar.net
License: UNKNOWN
Description: UNKNOWN
Platform: UNKNOWN

如果你想访问它,最好的方法是 pip 要么 pkg_resources (如亚历山大朱可夫所说) 例如:

>>> import pkg_resources
>>> d = pkg_resources.get_distribution('Foobar')
>>> d.version
'1.0'
>>> d.location
'/usr/lib/python2.7/site-packages'

3
2017-12-19 14:11



缺少实际读回元数据所需的步骤: d._get_metadata(d.PKG_INFO)  裸分发对象没有特别明显的访问信息的方式。 - amcgregor


这个数据的一个用途是它显示在Pypi上(http://pypi.python.org/如果你要在那里发布你的包裹。构建它的一种方法是这样的:

在你的顶级 foo 模块:

__author__= "me"
__version__= "1.0"
__description__= "foo package"

setup.py

import foo
setup(

    author = foo.__author__,
    version = foo.__version__,
    description = foo.__description__,
    packages = ["foo",],

)

这样,您只需要在一个位置更新元数据,并且当数据在包主模块中定义时,可以从那里访问它。


1
2017-12-19 14:17



这里有一个非常重要的捕获22。您的安装脚本现在取决于它已安装的软件包(或者至少已经可导入)。这不是一件好事。 (投票给有潜在危险的做法。) - amcgregor


特定 setup.py 如下:

from distutils.core import setup

setup(
    name         = 'TestApp',
    version      = '0.0.1',
    author       = 'saaj',
    py_modules   = ['app'],
    test_suite   = 'test'
)

对于某些脚本和自动化而不安装包,在哪里 pipeasy_install 乃至 setuptools 不提供命令行选项或公共API来读取所有元数据(例如 test_suite),这里有点hacky方式:

python3 -c "import sys, types; m = types.ModuleType('distutils.core'); \
    m.setup = lambda **kwargs: print(kwargs); \
    sys.modules['distutils.core'] = m; import setup" 

这将打印出来 dict 传递给的关键字参数 setup()

{'author': 'saaj', 'version': '0.0.1', 'name': 'TestApp', 
    'test_suite': 'test', 'py_modules': ['app']}

你可以替换 print 在里面 lambda 无论你需要什么输出。如果你的 setup.py 进口 setup() 从 setuptools,这实际上是推荐的方式,只需将“distutils.core”替换为代码片段中的“setuptools”即可。

格式化的代码段如下:

import sys
import types

m = types.ModuleType('distutils.core')
m.setup = lambda **kwargs: print(kwargs)
sys.modules['distutils.core'] = m

import setup  # import you setup.py with mocked setup()

0
2017-11-30 09:49