mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 07:31:38 +00:00 
			
		
		
		
	Issue #7457: added a read_pkg_file method to distutils.dist.DistributionMetadata so we can read back PKG-INFO files
This commit is contained in:
		
							parent
							
								
									8f254e7f6e
								
							
						
					
					
						commit
						a939ecd95b
					
				
					 5 changed files with 151 additions and 19 deletions
				
			
		| 
						 | 
				
			
			@ -285,6 +285,48 @@ by using the `docutils` parser::
 | 
			
		|||
    warning: check: Title underline too short. (line 2)
 | 
			
		||||
    warning: check: Could not finish the parsing.
 | 
			
		||||
 | 
			
		||||
Reading the metadata
 | 
			
		||||
=====================
 | 
			
		||||
 | 
			
		||||
The :func:`distutils.core.setup` function provides a command-line interface
 | 
			
		||||
that allows you to query the metadata fields of a project through the
 | 
			
		||||
`setup.py` script of a given project::
 | 
			
		||||
 | 
			
		||||
    $ python setup.py --name
 | 
			
		||||
    distribute
 | 
			
		||||
 | 
			
		||||
This call reads the `name` metadata by running the
 | 
			
		||||
:func:`distutils.core.setup`  function. Although, when a source or binary
 | 
			
		||||
distribution is created with Distutils, the metadata fields are written
 | 
			
		||||
in a static file called :file:`PKG-INFO`. When a Distutils-based project is
 | 
			
		||||
installed in Python, the :file:`PKG-INFO` file is copied alongside the modules
 | 
			
		||||
and packages of the distribution under :file:`NAME-VERSION-pyX.X.egg-info`,
 | 
			
		||||
where `NAME` is the name of the project, `VERSION` its version as defined
 | 
			
		||||
in the Metadata, and `pyX.X` the major and minor version of Python like
 | 
			
		||||
`2.7` or `3.2`.
 | 
			
		||||
 | 
			
		||||
You can read back this static file, by using the
 | 
			
		||||
:class:`distutils.dist.DistributionMetadata` class and its
 | 
			
		||||
:func:`read_pkg_file` method::
 | 
			
		||||
 | 
			
		||||
    >>> from distutils.dist import DistributionMetadata
 | 
			
		||||
    >>> metadata = DistributionMetadata()
 | 
			
		||||
    >>> metadata.read_pkg_file(open('distribute-0.6.8-py2.7.egg-info'))
 | 
			
		||||
    >>> metadata.name
 | 
			
		||||
    'distribute'
 | 
			
		||||
    >>> metadata.version
 | 
			
		||||
    '0.6.8'
 | 
			
		||||
    >>> metadata.description
 | 
			
		||||
    'Easily download, build, install, upgrade, and uninstall Python packages'
 | 
			
		||||
 | 
			
		||||
Notice that the class can also be instanciated with a metadata file path to
 | 
			
		||||
loads its values::
 | 
			
		||||
 | 
			
		||||
    >>> pkg_info_path = 'distribute-0.6.8-py2.7.egg-info'
 | 
			
		||||
    >>> DistributionMetadata(pkg_info_path).name
 | 
			
		||||
    'distribute'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.. % \section{Multiple extension modules}
 | 
			
		||||
.. % \label{multiple-ext}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -539,6 +539,10 @@ changes, or look through the Subversion logs for all the details.
 | 
			
		|||
  process, but instead simply not install the failing extension.
 | 
			
		||||
  (Contributed by Georg Brandl; :issue:`5583`.)
 | 
			
		||||
 | 
			
		||||
  Issue #7457: added a read_pkg_file method to.distutils.dist.DistributionMetadata
 | 
			
		||||
  see file:///MacDev/svn.python.org/python-trunk/Doc/build/html/distutils/examples.html#reading-the-metadata
 | 
			
		||||
  (:issue:`7457`, added by Tarek).
 | 
			
		||||
 | 
			
		||||
* The :class:`Fraction` class now accepts two rational numbers
 | 
			
		||||
  as arguments to its constructor.
 | 
			
		||||
  (Implemented by Mark Dickinson; :issue:`5812`.)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,7 @@
 | 
			
		|||
__revision__ = "$Id$"
 | 
			
		||||
 | 
			
		||||
import sys, os, re
 | 
			
		||||
import rfc822
 | 
			
		||||
 | 
			
		||||
try:
 | 
			
		||||
    import warnings
 | 
			
		||||
| 
						 | 
				
			
			@ -1006,6 +1007,20 @@ def is_pure(self):
 | 
			
		|||
    # to self.metadata.get_XXX.  The actual code is in the
 | 
			
		||||
    # DistributionMetadata class, below.
 | 
			
		||||
 | 
			
		||||
class _MetadataMessage(rfc822.Message):
 | 
			
		||||
 | 
			
		||||
    def read_field(self, name):
 | 
			
		||||
        value = self[name]
 | 
			
		||||
        if value == 'UNKNOWN':
 | 
			
		||||
            return None
 | 
			
		||||
        return value
 | 
			
		||||
 | 
			
		||||
    def getheaders(self, name, default):
 | 
			
		||||
        values = rfc822.Message.getheaders(self, name)
 | 
			
		||||
        if values == []:
 | 
			
		||||
            return None
 | 
			
		||||
        return values
 | 
			
		||||
 | 
			
		||||
class DistributionMetadata:
 | 
			
		||||
    """Dummy class to hold the distribution meta-data: name, version,
 | 
			
		||||
    author, and so forth.
 | 
			
		||||
| 
						 | 
				
			
			@ -1021,7 +1036,10 @@ class DistributionMetadata:
 | 
			
		|||
                         "provides", "requires", "obsoletes",
 | 
			
		||||
                         )
 | 
			
		||||
 | 
			
		||||
    def __init__ (self):
 | 
			
		||||
    def __init__(self, path=None):
 | 
			
		||||
        if path is not None:
 | 
			
		||||
            self.read_pkg_file(open(path))
 | 
			
		||||
        else:
 | 
			
		||||
            self.name = None
 | 
			
		||||
            self.version = None
 | 
			
		||||
            self.author = None
 | 
			
		||||
| 
						 | 
				
			
			@ -1041,6 +1059,45 @@ def __init__ (self):
 | 
			
		|||
            self.requires = None
 | 
			
		||||
            self.obsoletes = None
 | 
			
		||||
 | 
			
		||||
    def read_pkg_file(self, file):
 | 
			
		||||
        """Reads the metadata values from a file object."""
 | 
			
		||||
        msg = _MetadataMessage(file)
 | 
			
		||||
        metadata_version = msg['metadata-version']
 | 
			
		||||
        self.name = msg.read_field('name')
 | 
			
		||||
        self.version = msg.read_field('version')
 | 
			
		||||
        self.description = msg.read_field('summary')
 | 
			
		||||
        # we are filling author only.
 | 
			
		||||
        self.author = msg.read_field('author')
 | 
			
		||||
        self.maintainer = None
 | 
			
		||||
        self.author_email = msg.read_field('author-email')
 | 
			
		||||
        self.maintainer_email = None
 | 
			
		||||
        self.url = msg.read_field('home-page')
 | 
			
		||||
        self.license = msg.read_field('license')
 | 
			
		||||
 | 
			
		||||
        if 'download-url' in msg:
 | 
			
		||||
            self.download_url = msg.read_field('download-url')
 | 
			
		||||
        else:
 | 
			
		||||
            self.download_url = None
 | 
			
		||||
 | 
			
		||||
        self.long_description = msg.read_field('description')
 | 
			
		||||
        self.description = msg.read_field('summary')
 | 
			
		||||
 | 
			
		||||
        if 'keywords' in msg:
 | 
			
		||||
            self.keywords = msg.read_field('keywords').split(',')
 | 
			
		||||
 | 
			
		||||
        self.platforms = msg.getheaders('platform', None)
 | 
			
		||||
        self.classifiers = msg.getheaders('classifier', None)
 | 
			
		||||
 | 
			
		||||
        # PEP 314 - these fields only exist in 1.1
 | 
			
		||||
        if metadata_version == '1.1':
 | 
			
		||||
            self.requires = msg.getheaders('requires', None)
 | 
			
		||||
            self.provides = msg.getheaders('provides', None)
 | 
			
		||||
            self.obsoletes = msg.getheaders('obsoletes', None)
 | 
			
		||||
        else:
 | 
			
		||||
            self.requires = None
 | 
			
		||||
            self.provides = None
 | 
			
		||||
            self.obsoletes = None
 | 
			
		||||
 | 
			
		||||
    def write_pkg_info(self, base_dir):
 | 
			
		||||
        """Write the PKG-INFO file into the release tree.
 | 
			
		||||
        """
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,10 +8,9 @@
 | 
			
		|||
import warnings
 | 
			
		||||
import textwrap
 | 
			
		||||
 | 
			
		||||
from distutils.dist import Distribution, fix_help_options
 | 
			
		||||
from distutils.dist import Distribution, fix_help_options, DistributionMetadata
 | 
			
		||||
from distutils.cmd import Command
 | 
			
		||||
import distutils.dist
 | 
			
		||||
 | 
			
		||||
from test.test_support import TESTFN, captured_stdout
 | 
			
		||||
from distutils.tests import support
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -239,6 +238,7 @@ def _expander(path):
 | 
			
		|||
        # make sure --no-user-cfg disables the user cfg file
 | 
			
		||||
        self.assertEquals(len(all_files)-1, len(files))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MetadataTestCase(support.TempdirManager, support.EnvironGuard,
 | 
			
		||||
                       unittest.TestCase):
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -397,6 +397,33 @@ def test_long_description(self):
 | 
			
		|||
        meta = meta.replace('\n' + 8 * ' ', '\n')
 | 
			
		||||
        self.assertTrue(long_desc in meta)
 | 
			
		||||
 | 
			
		||||
    def test_read_metadata(self):
 | 
			
		||||
        attrs = {"name": "package",
 | 
			
		||||
                 "version": "1.0",
 | 
			
		||||
                 "long_description": "desc",
 | 
			
		||||
                 "description": "xxx",
 | 
			
		||||
                 "download_url": "http://example.com",
 | 
			
		||||
                 "keywords": ['one', 'two'],
 | 
			
		||||
                 "requires": ['foo']}
 | 
			
		||||
 | 
			
		||||
        dist = Distribution(attrs)
 | 
			
		||||
        metadata = dist.metadata
 | 
			
		||||
 | 
			
		||||
        # write it then reloads it
 | 
			
		||||
        PKG_INFO = StringIO.StringIO()
 | 
			
		||||
        metadata.write_pkg_file(PKG_INFO)
 | 
			
		||||
        PKG_INFO.seek(0)
 | 
			
		||||
        metadata.read_pkg_file(PKG_INFO)
 | 
			
		||||
 | 
			
		||||
        self.assertEquals(metadata.name, "package")
 | 
			
		||||
        self.assertEquals(metadata.version, "1.0")
 | 
			
		||||
        self.assertEquals(metadata.description, "xxx")
 | 
			
		||||
        self.assertEquals(metadata.download_url, 'http://example.com')
 | 
			
		||||
        self.assertEquals(metadata.keywords, ['one', 'two'])
 | 
			
		||||
        self.assertEquals(metadata.platforms, ['UNKNOWN'])
 | 
			
		||||
        self.assertEquals(metadata.obsoletes, None)
 | 
			
		||||
        self.assertEquals(metadata.requires, ['foo'])
 | 
			
		||||
 | 
			
		||||
def test_suite():
 | 
			
		||||
    suite = unittest.TestSuite()
 | 
			
		||||
    suite.addTest(unittest.makeSuite(DistributionTestCase))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,6 +15,8 @@ Core and Builtins
 | 
			
		|||
Library
 | 
			
		||||
-------
 | 
			
		||||
 | 
			
		||||
- Issue #7457: added a read_pkg_file method to 
 | 
			
		||||
  distutils.dist.DistributionMetadata.
 | 
			
		||||
 | 
			
		||||
What's New in Python 2.7 alpha 1
 | 
			
		||||
================================
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue