Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3492e39

Browse files
committed
Issue 19544 and Issue #7457: Restore the read_pkg_file method to distutils.dist.DistributionMetadata accidentally removed in the undo of distutils2.
1 parent a44372f commit 3492e39

4 files changed

Lines changed: 147 additions & 18 deletions

File tree

Doc/distutils/examples.rst

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,48 @@ by using the :mod:`docutils` parser::
284284
warning: check: Title underline too short. (line 2)
285285
warning: check: Could not finish the parsing.
286286

287+
Reading the metadata
288+
=====================
289+
290+
The :func:`distutils.core.setup` function provides a command-line interface
291+
that allows you to query the metadata fields of a project through the
292+
`setup.py` script of a given project::
293+
294+
$ python setup.py --name
295+
distribute
296+
297+
This call reads the `name` metadata by running the
298+
:func:`distutils.core.setup` function. Although, when a source or binary
299+
distribution is created with Distutils, the metadata fields are written
300+
in a static file called :file:`PKG-INFO`. When a Distutils-based project is
301+
installed in Python, the :file:`PKG-INFO` file is copied alongside the modules
302+
and packages of the distribution under :file:`NAME-VERSION-pyX.X.egg-info`,
303+
where `NAME` is the name of the project, `VERSION` its version as defined
304+
in the Metadata, and `pyX.X` the major and minor version of Python like
305+
`2.7` or `3.2`.
306+
307+
You can read back this static file, by using the
308+
:class:`distutils.dist.DistributionMetadata` class and its
309+
:func:`read_pkg_file` method::
310+
311+
>>> from distutils.dist import DistributionMetadata
312+
>>> metadata = DistributionMetadata()
313+
>>> metadata.read_pkg_file(open('distribute-0.6.8-py2.7.egg-info'))
314+
>>> metadata.name
315+
'distribute'
316+
>>> metadata.version
317+
'0.6.8'
318+
>>> metadata.description
319+
'Easily download, build, install, upgrade, and uninstall Python packages'
320+
321+
Notice that the class can also be instanciated with a metadata file path to
322+
loads its values::
323+
324+
>>> pkg_info_path = 'distribute-0.6.8-py2.7.egg-info'
325+
>>> DistributionMetadata(pkg_info_path).name
326+
'distribute'
327+
328+
287329
.. % \section{Multiple extension modules}
288330
.. % \label{multiple-ext}
289331

Lib/distutils/dist.py

Lines changed: 73 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"""
66

77
import sys, os, re
8+
from email import message_from_file
89

910
try:
1011
import warnings
@@ -999,25 +1000,80 @@ class DistributionMetadata:
9991000
"provides", "requires", "obsoletes",
10001001
)
10011002

1002-
def __init__ (self):
1003-
self.name = None
1004-
self.version = None
1005-
self.author = None
1006-
self.author_email = None
1003+
def __init__(self, path=None):
1004+
if path is not None:
1005+
self.read_pkg_file(open(path))
1006+
else:
1007+
self.name = None
1008+
self.version = None
1009+
self.author = None
1010+
self.author_email = None
1011+
self.maintainer = None
1012+
self.maintainer_email = None
1013+
self.url = None
1014+
self.license = None
1015+
self.description = None
1016+
self.long_description = None
1017+
self.keywords = None
1018+
self.platforms = None
1019+
self.classifiers = None
1020+
self.download_url = None
1021+
# PEP 314
1022+
self.provides = None
1023+
self.requires = None
1024+
self.obsoletes = None
1025+
1026+
def read_pkg_file(self, file):
1027+
"""Reads the metadata values from a file object."""
1028+
msg = message_from_file(file)
1029+
1030+
def _read_field(name):
1031+
value = msg[name]
1032+
if value == 'UNKNOWN':
1033+
return None
1034+
return value
1035+
1036+
def _read_list(name):
1037+
values = msg.get_all(name, None)
1038+
if values == []:
1039+
return None
1040+
return values
1041+
1042+
metadata_version = msg['metadata-version']
1043+
self.name = _read_field('name')
1044+
self.version = _read_field('version')
1045+
self.description = _read_field('summary')
1046+
# we are filling author only.
1047+
self.author = _read_field('author')
10071048
self.maintainer = None
1049+
self.author_email = _read_field('author-email')
10081050
self.maintainer_email = None
1009-
self.url = None
1010-
self.license = None
1011-
self.description = None
1012-
self.long_description = None
1013-
self.keywords = None
1014-
self.platforms = None
1015-
self.classifiers = None
1016-
self.download_url = None
1017-
# PEP 314
1018-
self.provides = None
1019-
self.requires = None
1020-
self.obsoletes = None
1051+
self.url = _read_field('home-page')
1052+
self.license = _read_field('license')
1053+
1054+
if 'download-url' in msg:
1055+
self.download_url = _read_field('download-url')
1056+
else:
1057+
self.download_url = None
1058+
1059+
self.long_description = _read_field('description')
1060+
self.description = _read_field('summary')
1061+
1062+
if 'keywords' in msg:
1063+
self.keywords = _read_field('keywords').split(',')
1064+
1065+
self.platforms = _read_list('platform')
1066+
self.classifiers = _read_list('classifier')
1067+
1068+
# PEP 314 - these fields only exist in 1.1
1069+
if metadata_version == '1.1':
1070+
self.requires = _read_list('requires')
1071+
self.provides = _read_list('provides')
1072+
self.obsoletes = _read_list('obsoletes')
1073+
else:
1074+
self.requires = None
1075+
self.provides = None
1076+
self.obsoletes = None
10211077

10221078
def write_pkg_info(self, base_dir):
10231079
"""Write the PKG-INFO file into the release tree.

Lib/distutils/tests/test_dist.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from unittest import mock
1010

11-
from distutils.dist import Distribution, fix_help_options
11+
from distutils.dist import Distribution, fix_help_options, DistributionMetadata
1212
from distutils.cmd import Command
1313

1414
from test.support import TESTFN, captured_stdout, run_unittest
@@ -388,6 +388,33 @@ def test_show_help(self):
388388
self.assertTrue(output)
389389

390390

391+
def test_read_metadata(self):
392+
attrs = {"name": "package",
393+
"version": "1.0",
394+
"long_description": "desc",
395+
"description": "xxx",
396+
"download_url": "http://example.com",
397+
"keywords": ['one', 'two'],
398+
"requires": ['foo']}
399+
400+
dist = Distribution(attrs)
401+
metadata = dist.metadata
402+
403+
# write it then reloads it
404+
PKG_INFO = io.StringIO()
405+
metadata.write_pkg_file(PKG_INFO)
406+
PKG_INFO.seek(0)
407+
metadata.read_pkg_file(PKG_INFO)
408+
409+
self.assertEquals(metadata.name, "package")
410+
self.assertEquals(metadata.version, "1.0")
411+
self.assertEquals(metadata.description, "xxx")
412+
self.assertEquals(metadata.download_url, 'http://example.com')
413+
self.assertEquals(metadata.keywords, ['one', 'two'])
414+
self.assertEquals(metadata.platforms, ['UNKNOWN'])
415+
self.assertEquals(metadata.obsoletes, None)
416+
self.assertEquals(metadata.requires, ['foo'])
417+
391418
def test_suite():
392419
suite = unittest.TestSuite()
393420
suite.addTest(unittest.makeSuite(DistributionTestCase))

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ Core and Builtins
1313
Library
1414
-------
1515

16+
- Issue #19544 and Issue #7457: Restore the read_pkg_file method to
17+
distutils.dist.DistributionMetadata accidentally removed in the undo of
18+
distutils2.
19+
1620
- Issue #1575020: Fixed support of 24-bit wave files on big-endian platforms.
1721

1822
- Issue #19480: HTMLParser now accepts all valid start-tag names as defined

0 commit comments

Comments
 (0)