pkginfo-1.2.1/0000775000175000017500000000000012451564507014327 5ustar tseavertseaver00000000000000pkginfo-1.2.1/setup.cfg0000664000175000017500000000032412451564507016147 0ustar tseavertseaver00000000000000[easy_install] zip_ok = false [nosetests] nocapture = 1 cover-package = pkginfo cover-erase = 1 [aliases] dev = develop easy_install pkginfo[testing] [egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 pkginfo-1.2.1/PKG-INFO0000664000175000017500000002024712451564507015431 0ustar tseavertseaver00000000000000Metadata-Version: 1.1 Name: pkginfo Version: 1.2.1 Summary: Query metadatdata from sdists / bdists / installed packages. Home-page: http://pypi.python.org/pypi/pkginfo/ Author: Tres Seaver, Agendaless Consulting Author-email: tseaver@agendaless.com License: Python Description: ``pkginfo`` README ================== This package provides an API for querying the distutils metadata written in the ``PKG-INFO`` file inside a source distriubtion (an ``sdist``) or a binary distribution (e.g., created by running ``bdist_egg``). It can also query the ``EGG-INFO`` directory of an installed distribution, and the ``*.egg-info`` stored in a "development checkout" (e.g, created by running ``setup.py develop``). Please see the `pkginfo docs `_ for detailed documentation. ``pkginfo`` Changelog ===================== 1.2.1 (2014-01-02) ------------------ - Add overlooked Trove classifier for Python 3.4. 1.2 (2014-01-02) ---------------- - Add support for Python 3.4, PyPy3. - Add 100% coverage for ``pkginfo.commandline`` module. 1.2b1 (2013-12-05) ------------------ - Add support for the "wheel" distribution format, along with minimal metadata 2.0 support (not including new PEP 426 JSON properties). Code (re-)borrowed from Donald Stuft's ``twine`` package. 1.1 (2013-10-09) ---------------- - Fix tests to pass with current PyPy releases. 1.1b1 (2013-05-05) ------------------ - Support "develop" packages which keep their ``*.egg-info`` in a subdirectory. See https://bugs.launchpad.net/pkginfo/+bug/919147. - Add support for "unpacked SDists" (thanks to Mike Lundy for the patch). 1.0 (2013-05-05) ---------------- - No changes from 1.0b2. 1.0b2 (2012-12-28) ------------------ - Suppress resource warning leaks reported against clients. - Fix 'commandline' module under Py3k. 1.0b1 (2012-12-28) ------------------ - Add support for Python 3.2 and 3.3, including testing them under ``tox``. - Add support for PyPy, including testing it under ``tox``. - Test supported Python versions under ``tox``. - Drop support for Python 2.5. - Add a ``setup.py dev`` alias: runs ``setup.py develop`` and installs testing extras (``nose`` and ``coverage``). 0.9.1 (2012-10-22) ------------------ - Fix test failure under Python >= 2.7, which is enforcing 'metadata_version == 1.1' because we have classifiers. 0.9 (2012-04-25) ---------------- - Fix introspection of installed namespace packages. They may be installed as eggs or via dist-installed 'egg-info' files. https://bugs.launchpad.net/pkginfo/+bug/934311 - Avoid a regression in 0.8 under Python 2.6 / 2.7 when parsing unicode. https://bugs.launchpad.net/pkginfo/+bug/733827/comments/3 0.8 (2011-03-12) ---------------- - Work around Python 2.7's breakage of StringIO. Fixes https://bugs.launchpad.net/pkginfo/+bug/733827 - Fix bug in introspection of installed packages missing the ``__package__`` attribute. 0.7 (2010-11-04) ---------------- - Preserve newlines in the ``description`` field. Thanks to Sridhar Ratnakumar for the patch. - 100% test coverage. 0.6 (2010-06-01) ---------------- - Replace use of ``StringIO.StringIO`` with ``io.StringIO``, where available (Python >= 2.6). - Replace use of ``rfc822`` stdlib module with ``email.parser``, when available (Python >= 2.5). Ensured that distributions "unfold" wrapped continuation lines, stripping any leading / trailing whitespace, no matter which module was used for parsing. - Remove bogus testing dependency on ``zope.testing``. - Add tests that the "environment markers" spelled out in the approved PEP 345 are captured. - Add ``Project-URL`` for ``1.2`` PKG-INFO metdata (defined in the accepted version of PEP 345). 0.5 (2009-09-11) ---------------- - Marked package as non-zip-safe. - Fix Trove metadata misspelling. - Restore compatibility with Python 2.4. - Note that the introspection of installed packages / modules works only in Python 2.6 or later. - Add ``Index`` class as an abstraction over a collection of distributions. - Add ``download_url_prefix`` argument to ``pkginfo`` script. If passed, the script will use the prefix to synthesize a ``download_url`` for distributions which do not supply that value directly. 0.4.1 (2009-05-07) ------------------ - Fix bugs in handling of installed packages which lack ``__file__`` or ``PKG-INFO``. 0.4 (2009-05-07) ---------------- - Extend the console script to allow output as CSV or INI. Also, added arguments to specify the metadata version and other parsing / output policies. - Add support for the different metadata versions specified in PEPs 241, 314, and 345. Distributions now parse and expose only the attributes corresponding to their metadata version, which defaults to the version parsed from the ``PKG-INFO`` file. The programmer can override that version when creating the distribution object. 0.3 (2009-05-07) ---------------- - Add support for introspection of "development eggs" (checkouts with ``PKG-INFO``, perhaps created via ``setup.py develop``). - Add a console script, ``pkginfo``, which takes one or more paths on the command line and writes out the associated information. Thanks to ``runeh`` for the patch! - Add ``get_metadata`` helper function, which dispatches a given path or module across the available distribution types, and returns a distribution object. Thanks to ``runeh`` for the patch! - Make distribution objects support iteration over the metadata fields. Thanks to ``runeh`` for the patch! - Make ``Distribution`` and subclasses new-style classes. Thanks to ``runeh`` for the patch! 0.2 (2009-04-14) ---------------- - Add support for introspection of ``bdist_egg`` binary distributions. 0.1.1 (2009-04-10) ------------------ - Fix packaging errors. 0.1 (2009-04-10) ---------------- - Initial release. Keywords: distribution sdist installed metadata Platform: Unix Platform: Windows Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Python Software Foundation License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.2 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: System :: Software Distribution pkginfo-1.2.1/tox.ini0000664000175000017500000000175712451560067015651 0ustar tseavertseaver00000000000000[tox] envlist = # py26,py27,py32,py33,pypy,cover py26,py27,pypy,py32,py33,py34,pypy3,cover2,cover3,docs [testenv] commands = python setup.py develop python setup.py test -q [testenv:cover2] basepython = python2.6 commands = python setup.py develop python setup.py nosetests --with-xunit --with-xcoverage deps = nose coverage nosexcover [testenv:cover3] basepython = python3.2 commands = python setup.py develop python setup.py nosetests --with-xunit --with-xcoverage deps = nose coverage nosexcover [testenv:docs] basepython = python2.6 commands = sphinx-build -b html -d docs/_build/doctrees docs docs/_build/html sphinx-build -b doctest -d docs/_build/doctrees docs docs/_build/doctest deps = Sphinx # we separate coverage into its own testenv because a) "last run wins" wrt # cobertura jenkins reporting and b) pypy and jython can't handle any # combination of versions of coverage and nosexcover that i can find. pkginfo-1.2.1/setup.py0000644000175000017500000000330412451564426016037 0ustar tseavertseaver00000000000000import os try: from setuptools import setup except ImportError: from distutils.core import setup extras = {} else: extras = { 'test_suite': 'pkginfo.tests', 'zip_safe': False, 'extras_require': { 'testing': ['nose', 'coverage'], }, } here = os.path.abspath(os.path.dirname(__file__)) README = open(os.path.join(here, 'README.txt')).read() CHANGES = open(os.path.join(here, 'CHANGES.txt')).read() setup( name='pkginfo', version='1.2.1', description='Query metadatdata from sdists / bdists / installed packages.', platforms=['Unix', 'Windows'], long_description='\n\n'.join([README, CHANGES]), keywords='distribution sdist installed metadata', url='http://pypi.python.org/pypi/pkginfo/', author='Tres Seaver, Agendaless Consulting', author_email='tseaver@agendaless.com', license='Python', classifiers=[ 'Intended Audience :: Developers', 'License :: OSI Approved :: Python Software Foundation License', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: System :: Software Distribution', ], entry_points={ 'console_scripts': [ ['pkginfo = pkginfo.commandline:main'] ] }, packages=['pkginfo', 'pkginfo.tests'], **extras ) pkginfo-1.2.1/.bzrignore0000644000175000017500000000013412451562305016317 0ustar tseavertseaver00000000000000*.egg-info ./build ./dist .coverage __pycache__ .tox coverage.xml nosetests.xml docs/_build pkginfo-1.2.1/pkginfo.egg-info/0000775000175000017500000000000012451564507017456 5ustar tseavertseaver00000000000000pkginfo-1.2.1/pkginfo.egg-info/top_level.txt0000664000175000017500000000001012451564506022176 0ustar tseavertseaver00000000000000pkginfo pkginfo-1.2.1/pkginfo.egg-info/SOURCES.txt0000664000175000017500000000366012451564507021347 0ustar tseavertseaver00000000000000.bzrignore CHANGES.txt README.txt TODO.txt setup.cfg setup.py tox.ini docs/Makefile docs/conf.py docs/distributions.rst docs/index.rst docs/indexes.rst docs/metadata.rst docs/examples/mypackage-0.1-cp26-none-linux_x86_64.whl docs/examples/mypackage-0.1-py2.6.egg docs/examples/mypackage-0.1.tar.bz2 docs/examples/mypackage-0.1.tar.gz docs/examples/mypackage-0.1.zip docs/examples/nodistinfo-0.1-any.whl docs/examples/nopkginfo-0.1.egg docs/examples/nopkginfo-0.1.zip docs/examples/mypackage-0.1/PKG-INFO docs/examples/mypackage-0.1/README.txt docs/examples/mypackage-0.1/setup.cfg docs/examples/mypackage-0.1/setup.py pkginfo/__init__.py pkginfo/_compat.py pkginfo/bdist.py pkginfo/commandline.py pkginfo/develop.py pkginfo/distribution.py pkginfo/index.py pkginfo/installed.py pkginfo/sdist.py pkginfo/utils.py pkginfo/wheel.py pkginfo.egg-info/PKG-INFO pkginfo.egg-info/SOURCES.txt pkginfo.egg-info/dependency_links.txt pkginfo.egg-info/entry_points.txt pkginfo.egg-info/not-zip-safe pkginfo.egg-info/requires.txt pkginfo.egg-info/top_level.txt pkginfo/tests/__init__.py pkginfo/tests/test_bdist.py pkginfo/tests/test_commandline.py pkginfo/tests/test_develop.py pkginfo/tests/test_distribution.py pkginfo/tests/test_index.py pkginfo/tests/test_installed.py pkginfo/tests/test_sdist.py pkginfo/tests/test_utils.py pkginfo/tests/test_wheel.py pkginfo/tests/funny/__init__.py pkginfo/tests/funny/funny.egg-info pkginfo/tests/manky/NOT-A-PACKAGE.txt pkginfo/tests/manky/namespaced/__init__.py pkginfo/tests/manky/namespaced.manky-0.1.egg-info/PKG-INFO pkginfo/tests/manky/namespaced/manky/__init__.py pkginfo/tests/silly/PKG-INFO pkginfo/tests/sneaky/NOT-A-PACKAGE.txt pkginfo/tests/sneaky/setup.py pkginfo/tests/sneaky/src/namespaced/__init__.py pkginfo/tests/sneaky/src/namespaced/sneaky/__init__.py pkginfo/tests/wonky/NOT-A-PACKAGE.txt pkginfo/tests/wonky/EGG-INFO/PKG-INFO pkginfo/tests/wonky/namespaced/__init__.py pkginfo/tests/wonky/namespaced/wonky/__init__.pypkginfo-1.2.1/pkginfo.egg-info/PKG-INFO0000664000175000017500000002024712451564506020557 0ustar tseavertseaver00000000000000Metadata-Version: 1.1 Name: pkginfo Version: 1.2.1 Summary: Query metadatdata from sdists / bdists / installed packages. Home-page: http://pypi.python.org/pypi/pkginfo/ Author: Tres Seaver, Agendaless Consulting Author-email: tseaver@agendaless.com License: Python Description: ``pkginfo`` README ================== This package provides an API for querying the distutils metadata written in the ``PKG-INFO`` file inside a source distriubtion (an ``sdist``) or a binary distribution (e.g., created by running ``bdist_egg``). It can also query the ``EGG-INFO`` directory of an installed distribution, and the ``*.egg-info`` stored in a "development checkout" (e.g, created by running ``setup.py develop``). Please see the `pkginfo docs `_ for detailed documentation. ``pkginfo`` Changelog ===================== 1.2.1 (2014-01-02) ------------------ - Add overlooked Trove classifier for Python 3.4. 1.2 (2014-01-02) ---------------- - Add support for Python 3.4, PyPy3. - Add 100% coverage for ``pkginfo.commandline`` module. 1.2b1 (2013-12-05) ------------------ - Add support for the "wheel" distribution format, along with minimal metadata 2.0 support (not including new PEP 426 JSON properties). Code (re-)borrowed from Donald Stuft's ``twine`` package. 1.1 (2013-10-09) ---------------- - Fix tests to pass with current PyPy releases. 1.1b1 (2013-05-05) ------------------ - Support "develop" packages which keep their ``*.egg-info`` in a subdirectory. See https://bugs.launchpad.net/pkginfo/+bug/919147. - Add support for "unpacked SDists" (thanks to Mike Lundy for the patch). 1.0 (2013-05-05) ---------------- - No changes from 1.0b2. 1.0b2 (2012-12-28) ------------------ - Suppress resource warning leaks reported against clients. - Fix 'commandline' module under Py3k. 1.0b1 (2012-12-28) ------------------ - Add support for Python 3.2 and 3.3, including testing them under ``tox``. - Add support for PyPy, including testing it under ``tox``. - Test supported Python versions under ``tox``. - Drop support for Python 2.5. - Add a ``setup.py dev`` alias: runs ``setup.py develop`` and installs testing extras (``nose`` and ``coverage``). 0.9.1 (2012-10-22) ------------------ - Fix test failure under Python >= 2.7, which is enforcing 'metadata_version == 1.1' because we have classifiers. 0.9 (2012-04-25) ---------------- - Fix introspection of installed namespace packages. They may be installed as eggs or via dist-installed 'egg-info' files. https://bugs.launchpad.net/pkginfo/+bug/934311 - Avoid a regression in 0.8 under Python 2.6 / 2.7 when parsing unicode. https://bugs.launchpad.net/pkginfo/+bug/733827/comments/3 0.8 (2011-03-12) ---------------- - Work around Python 2.7's breakage of StringIO. Fixes https://bugs.launchpad.net/pkginfo/+bug/733827 - Fix bug in introspection of installed packages missing the ``__package__`` attribute. 0.7 (2010-11-04) ---------------- - Preserve newlines in the ``description`` field. Thanks to Sridhar Ratnakumar for the patch. - 100% test coverage. 0.6 (2010-06-01) ---------------- - Replace use of ``StringIO.StringIO`` with ``io.StringIO``, where available (Python >= 2.6). - Replace use of ``rfc822`` stdlib module with ``email.parser``, when available (Python >= 2.5). Ensured that distributions "unfold" wrapped continuation lines, stripping any leading / trailing whitespace, no matter which module was used for parsing. - Remove bogus testing dependency on ``zope.testing``. - Add tests that the "environment markers" spelled out in the approved PEP 345 are captured. - Add ``Project-URL`` for ``1.2`` PKG-INFO metdata (defined in the accepted version of PEP 345). 0.5 (2009-09-11) ---------------- - Marked package as non-zip-safe. - Fix Trove metadata misspelling. - Restore compatibility with Python 2.4. - Note that the introspection of installed packages / modules works only in Python 2.6 or later. - Add ``Index`` class as an abstraction over a collection of distributions. - Add ``download_url_prefix`` argument to ``pkginfo`` script. If passed, the script will use the prefix to synthesize a ``download_url`` for distributions which do not supply that value directly. 0.4.1 (2009-05-07) ------------------ - Fix bugs in handling of installed packages which lack ``__file__`` or ``PKG-INFO``. 0.4 (2009-05-07) ---------------- - Extend the console script to allow output as CSV or INI. Also, added arguments to specify the metadata version and other parsing / output policies. - Add support for the different metadata versions specified in PEPs 241, 314, and 345. Distributions now parse and expose only the attributes corresponding to their metadata version, which defaults to the version parsed from the ``PKG-INFO`` file. The programmer can override that version when creating the distribution object. 0.3 (2009-05-07) ---------------- - Add support for introspection of "development eggs" (checkouts with ``PKG-INFO``, perhaps created via ``setup.py develop``). - Add a console script, ``pkginfo``, which takes one or more paths on the command line and writes out the associated information. Thanks to ``runeh`` for the patch! - Add ``get_metadata`` helper function, which dispatches a given path or module across the available distribution types, and returns a distribution object. Thanks to ``runeh`` for the patch! - Make distribution objects support iteration over the metadata fields. Thanks to ``runeh`` for the patch! - Make ``Distribution`` and subclasses new-style classes. Thanks to ``runeh`` for the patch! 0.2 (2009-04-14) ---------------- - Add support for introspection of ``bdist_egg`` binary distributions. 0.1.1 (2009-04-10) ------------------ - Fix packaging errors. 0.1 (2009-04-10) ---------------- - Initial release. Keywords: distribution sdist installed metadata Platform: Unix Platform: Windows Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Python Software Foundation License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.2 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: System :: Software Distribution pkginfo-1.2.1/pkginfo.egg-info/dependency_links.txt0000664000175000017500000000000112451564506023523 0ustar tseavertseaver00000000000000 pkginfo-1.2.1/pkginfo.egg-info/not-zip-safe0000664000175000017500000000000112041300263021662 0ustar tseavertseaver00000000000000 pkginfo-1.2.1/pkginfo.egg-info/requires.txt0000664000175000017500000000003112451564506022047 0ustar tseavertseaver00000000000000 [testing] nose coverage pkginfo-1.2.1/pkginfo.egg-info/entry_points.txt0000664000175000017500000000006612451564506022755 0ustar tseavertseaver00000000000000[console_scripts] pkginfo = pkginfo.commandline:main pkginfo-1.2.1/README.txt0000644000175000017500000000102012141501613015775 0ustar tseavertseaver00000000000000``pkginfo`` README ================== This package provides an API for querying the distutils metadata written in the ``PKG-INFO`` file inside a source distriubtion (an ``sdist``) or a binary distribution (e.g., created by running ``bdist_egg``). It can also query the ``EGG-INFO`` directory of an installed distribution, and the ``*.egg-info`` stored in a "development checkout" (e.g, created by running ``setup.py develop``). Please see the `pkginfo docs `_ for detailed documentation. pkginfo-1.2.1/TODO.txt0000644000175000017500000000054611357450726015641 0ustar tseavertseaver00000000000000TODOs ===== - [X] Catch up to latest changes in PEP345: * Project-URL header * "environment markers" - [_] Add APIs to ``Distribution`` which expose the semantics of the requirement versions and environment markers. - [_] Allow the ``pkginfo`` script to process URLs. - [_] Allow the ``pkginfo`` script to process requirements specs. pkginfo-1.2.1/pkginfo/0000775000175000017500000000000012451564507015764 5ustar tseavertseaver00000000000000pkginfo-1.2.1/pkginfo/bdist.py0000644000175000017500000000226512067413246017442 0ustar tseavertseaver00000000000000import os import zipfile from pkginfo.distribution import Distribution class BDist(Distribution): def __init__(self, filename, metadata_version=None): self.filename = filename self.metadata_version = metadata_version self.extractMetadata() def read(self): fqn = os.path.abspath( os.path.normpath(self.filename)) if not os.path.exists(fqn): raise ValueError('No such file: %s' % fqn) if fqn.endswith('.egg'): archive = zipfile.ZipFile(fqn) names = archive.namelist() def read_file(name): return archive.read(name) else: raise ValueError('Not a known archive format: %s' % fqn) try: tuples = [x.split('/') for x in names if 'PKG-INFO' in x] schwarz = sorted([(len(x), x) for x in tuples]) for path in [x[1] for x in schwarz]: candidate = '/'.join(path) data = read_file(candidate) if b'Metadata-Version' in data: return data finally: archive.close() raise ValueError('No PKG-INFO in archive: %s' % fqn) pkginfo-1.2.1/pkginfo/index.py0000644000175000017500000000101511357450726017441 0ustar tseavertseaver00000000000000from pkginfo.distribution import Distribution class Index(dict): def __setitem__(self, key, value): if not isinstance(value, Distribution): raise ValueError('Not a distribution: %r.' % value) if key != '%s-%s' % (value.name, value.version): raise ValueError('Key must match -.') super(Index, self).__setitem__(key, value) def add(self, distribution): key = '%s-%s' % (distribution.name, distribution.version) self[key] = distribution pkginfo-1.2.1/pkginfo/_compat.py0000664000175000017500000000156512141476451017763 0ustar tseavertseaver00000000000000try: STRING_TYPES = (str, unicode) except NameError: #pragma NO COVER Python >= 3.0 STRING_TYPES = (str,) try: u = unicode except NameError: #pragma NO COVER Python >= 3.0 u = str b = bytes else: #pragma NO COVER Python < 3.0 b = str try: from StringIO import StringIO except ImportError: #pragma NO COVER Python >= 3.0 from io import StringIO from io import BytesIO else: #pragma NO COVER Python < 3.0 BytesIO = StringIO def must_decode(value): #pragma NO COVER if type(value) is bytes: try: return value.decode('utf-8') except UnicodeDecodeError: return value.decode('latin1') return value def must_encode(value): #pragma NO COVER if type(value) is u: return value.encode('utf-8') return value pkginfo-1.2.1/pkginfo/__init__.py0000644000175000017500000000051112245465756020077 0ustar tseavertseaver00000000000000from pkginfo.bdist import BDist from pkginfo.develop import Develop from pkginfo.distribution import Distribution from pkginfo.index import Index from pkginfo.installed import Installed from pkginfo.sdist import SDist from pkginfo.sdist import UnpackedSDist from pkginfo.utils import get_metadata from pkginfo.wheel import Wheel pkginfo-1.2.1/pkginfo/installed.py0000644000175000017500000000370312067400606020306 0ustar tseavertseaver00000000000000import glob import os import sys import warnings from pkginfo.distribution import Distribution from pkginfo._compat import STRING_TYPES class Installed(Distribution): def __init__(self, package, metadata_version=None): if isinstance(package, STRING_TYPES): self.package_name = package try: __import__(package) except ImportError: package = None else: package = sys.modules[package] else: self.package_name = package.__name__ self.package = package self.metadata_version = metadata_version self.extractMetadata() def read(self): opj = os.path.join if self.package is not None: package = self.package.__package__ if package is None: package = self.package.__name__ pattern = '%s*.egg-info' % package file = getattr(self.package, '__file__', None) if file is not None: candidates = [] def _add_candidate(where): candidates.extend(glob.glob(where)) for entry in sys.path: if file.startswith(entry): _add_candidate(opj(entry, 'EGG-INFO')) # egg? _add_candidate(opj(entry, pattern)) # dist-installed? dir, name = os.path.split(self.package.__file__) _add_candidate(opj(dir, pattern)) _add_candidate(opj(dir, '..', pattern)) for candidate in candidates: if os.path.isdir(candidate): path = opj(candidate, 'PKG-INFO') else: path = candidate if os.path.exists(path): with open(path) as f: return f.read() warnings.warn('No PKG-INFO found for package: %s' % self.package_name) pkginfo-1.2.1/pkginfo/distribution.py0000644000175000017500000000751112245465263021057 0ustar tseavertseaver00000000000000from email.parser import Parser from pkginfo._compat import StringIO from pkginfo._compat import must_decode def parse(fp): return Parser().parse(fp) def get(msg, header): return _collapse_leading_ws(header, msg.get(header)) def get_all(msg, header): return [_collapse_leading_ws(header, x) for x in msg.get_all(header)] def _collapse_leading_ws(header, txt): """ ``Description`` header must preserve newlines; all others need not """ if header.lower() == 'description': # preserve newlines return '\n'.join([x[8:] if x.startswith(' ' * 8) else x for x in txt.strip().splitlines()]) else: return ' '.join([x.strip() for x in txt.splitlines()]) HEADER_ATTRS_1_0 = ( # PEP 241 ('Metadata-Version', 'metadata_version', False), ('Name', 'name', False), ('Version', 'version', False), ('Platform', 'platforms', True), ('Supported-Platform', 'supported_platforms', True), ('Summary', 'summary', False), ('Description', 'description', False), ('Keywords', 'keywords', False), ('Home-Page', 'home_page', False), ('Author', 'author', False), ('Author-email', 'author_email', False), ('License', 'license', False), ) HEADER_ATTRS_1_1 = HEADER_ATTRS_1_0 + ( # PEP 314 ('Classifier', 'classifiers', True), ('Download-URL', 'download_url', False), ('Requires', 'requires', True), ('Provides', 'provides', True), ('Obsoletes', 'obsoletes', True), ) HEADER_ATTRS_1_2 = HEADER_ATTRS_1_1 + ( # PEP 345 ('Maintainer', 'maintainer', False), ('Maintainer-email', 'maintainer_email', False), ('Requires-Python', 'requires_python', False), ('Requires-External', 'requires_external', True), ('Requires-Dist', 'requires_dist', True), ('Provides-Dist', 'provides_dist', True), ('Obsoletes-Dist', 'obsoletes_dist', True), ('Project-URL', 'project_urls', True), ) HEADER_ATTRS_2_0 = HEADER_ATTRS_1_2 #XXX PEP 426? HEADER_ATTRS = { '1.0': HEADER_ATTRS_1_0, '1.1': HEADER_ATTRS_1_1, '1.2': HEADER_ATTRS_1_2, '2.0': HEADER_ATTRS_2_0, } class Distribution(object): metadata_version = None # version 1.0 name = None version = None platforms = () supported_platforms = () summary = None description = None keywords = None home_page = None download_url = None author = None author_email = None license = None # version 1.1 classifiers = () requires = () provides = () obsoletes = () # version 1.2 maintainer = None maintainer_email = None requires_python = None requires_external = () requires_dist = () provides_dist = () obsoletes_dist = () project_urls = () def extractMetadata(self): data = self.read() self.parse(data) def read(self): raise NotImplementedError def _getHeaderAttrs(self): return HEADER_ATTRS.get(self.metadata_version, []) def parse(self, data): fp = StringIO(must_decode(data)) msg = parse(fp) if 'Metadata-Version' in msg and self.metadata_version is None: value = get(msg, 'Metadata-Version') metadata_version = self.metadata_version = value for header_name, attr_name, multiple in self._getHeaderAttrs(): if attr_name == 'metadata_version': continue if header_name in msg: if multiple: values = get_all(msg, header_name) setattr(self, attr_name, values) else: value = get(msg, header_name) if value != 'UNKNOWN': setattr(self, attr_name, value) def __iter__(self): for header_name, attr_name, multiple in self._getHeaderAttrs(): yield attr_name iterkeys = __iter__ pkginfo-1.2.1/pkginfo/tests/0000775000175000017500000000000012451564507017126 5ustar tseavertseaver00000000000000pkginfo-1.2.1/pkginfo/tests/test_commandline.py0000664000175000017500000002350612451555205023026 0ustar tseavertseaver00000000000000import unittest class Test__parse_options(unittest.TestCase): def _callFUT(self, args): from pkginfo.commandline import _parse_options return _parse_options(args) def test_empty(self): import io import sys from pkginfo.commandline import __doc__ as usage firstline = usage.splitlines()[0] # parse_args emits "native" error output. if sys.version_info[0] < 3: buf = io.BytesIO() else: buf = io.StringIO() with _Monkey(sys, stderr=buf): self.assertRaises(SystemExit, self._callFUT, []) self.assertTrue(firstline in buf.getvalue()) def test_nonempty(self): options, args = self._callFUT(['foo']) self.assertEqual(args, ['foo']) class BaseTests(unittest.TestCase): def _getTargetClass(self): from pkginfo.commandline import Base return Base def _makeOne(self, options): return self._getTargetClass()(options) def test___init___defaults(self): base = self._makeOne(_Options(fields=())) self.assertTrue(base._fields is None) def test___init___w_fields(self): fields = object() base = self._makeOne(_Options(fields=fields)) self.assertTrue(base._fields is fields) class _FormatterBase(object): def _capture_output(self, func, *args, **kw): import io import sys # Emulate stdout as wanting "native" strings if sys.version_info[0] < 3: buf = io.BytesIO() else: buf = io.StringIO() with _Monkey(sys, stdout=buf): func(*args, **kw) return buf.getvalue() def _no_output(self, simple, meta): import sys with _Monkey(sys, stdout=object()): # raise if write simple(meta) class SimpleTests(unittest.TestCase, _FormatterBase): def _getTargetClass(self): from pkginfo.commandline import Simple return Simple def _makeOne(self, options): return self._getTargetClass()(options) def test___init___(self): simple = self._makeOne(_Options(fields=None, skip=True)) self.assertTrue(simple._skip) def test___call___w_empty_fields(self): simple = self._makeOne(_Options(fields=(), skip=False)) meta = _Meta() self._no_output(simple, meta) def test___call___w_skip_and_value_None_no_fields(self): simple = self._makeOne(_Options(fields=(), skip=True)) meta = _Meta(foo=None) self._no_output(simple, meta) def test___call___w_skip_and_value_empty_tuple_explicit_fields(self): simple = self._makeOne(_Options(fields=('foo',), skip=True)) meta = _Meta(foo=(), bar='Bar') self._no_output(simple, meta) def test___call___w_skip_but_values_explicit_fields(self): simple = self._makeOne(_Options(fields=('foo',), skip=True)) meta = _Meta(foo='Foo') output = self._capture_output(simple, meta) self.assertEqual(output, 'foo: Foo\n') class SingleLineTests(unittest.TestCase, _FormatterBase): def _getTargetClass(self): from pkginfo.commandline import SingleLine return SingleLine def _makeOne(self, options): return self._getTargetClass()(options) def test___init___(self): single = self._makeOne( _Options(fields=None, item_delim='I', sequence_delim='S')) self.assertEqual(single._item_delim, 'I') self.assertEqual(single._sequence_delim, 'S') def test___call__wo_fields_wo_list(self): single = self._makeOne( _Options(fields=(), item_delim='|', sequence_delim=object())) # raise if used meta = _Meta(foo='Foo', bar='Bar') output = self._capture_output(single, meta) self.assertEqual(output, 'Bar|Foo\n') def test___call__w_fields_w_list(self): single = self._makeOne( _Options(fields=('foo', 'bar'), item_delim='|', sequence_delim='*')) meta = _Meta(foo='Foo', bar=['Bar1', 'Bar2'], baz='Baz') output = self._capture_output(single, meta) self.assertEqual(output, 'Foo|Bar1*Bar2\n') class CSVTests(unittest.TestCase, _FormatterBase): def _getTargetClass(self): from pkginfo.commandline import CSV return CSV def _makeOne(self, options): return self._getTargetClass()(options) def test___init___(self): csv = self._makeOne( _Options(fields=None, sequence_delim='S')) self.assertEqual(csv._sequence_delim, 'S') def test___call__wo_fields_wo_list(self): meta = _Meta(foo='Foo', bar='Bar') csv = self._makeOne( _Options(fields=None, sequence_delim=object())) # raise if used output = self._capture_output(csv, meta) self.assertEqual(output, 'bar,foo\r\nBar,Foo\r\n') def test___call__w_fields_w_list(self): meta = _Meta(foo='Foo', bar=['Bar1', 'Bar2'], baz='Baz') csv = self._makeOne( _Options(fields=('foo', 'bar'), item_delim='|', sequence_delim='*')) output = self._capture_output(csv, meta) self.assertEqual(output, 'foo,bar\r\nFoo,Bar1*Bar2\r\n') class INITests(unittest.TestCase, _FormatterBase): def _getTargetClass(self): from pkginfo.commandline import INI return INI def _makeOne(self, options): return self._getTargetClass()(options) def test___call___duplicate(self): ini = self._makeOne(_Options(fields=('foo',))) meta = _Meta(name='foo', version='0.1', foo='Foo') ini._parser.add_section('foo-0.1') self.assertRaises(ValueError, ini, meta) def test___call___wo_fields_wo_list(self): ini = self._makeOne(_Options(fields=None)) meta = _Meta(name='foo', version='0.1', foo='Foo') ini(meta) cp = ini._parser self.assertEqual(cp.sections(), ['foo-0.1']) self.assertEqual(sorted(cp.options('foo-0.1')), ['foo', 'name', 'version']) self.assertEqual(cp.get('foo-0.1', 'name'), 'foo') self.assertEqual(cp.get('foo-0.1', 'version'), '0.1') self.assertEqual(cp.get('foo-0.1', 'foo'), 'Foo') def test___call___w_fields_w_list(self): ini = self._makeOne(_Options(fields=('foo', 'bar'))) meta = _Meta(name='foo', version='0.1', foo='Foo', bar=['Bar1', 'Bar2'], baz='Baz') ini(meta) cp = ini._parser self.assertEqual(cp.sections(), ['foo-0.1']) self.assertEqual(sorted(cp.options('foo-0.1')), ['bar', 'foo']) self.assertEqual(cp.get('foo-0.1', 'foo'), 'Foo') self.assertEqual(cp.get('foo-0.1', 'bar'), 'Bar1\n\tBar2') class Test_main(unittest.TestCase): def _callFUT(self, args, monkey='simple'): from pkginfo.commandline import main from pkginfo.commandline import _FORMATTERS before = _FORMATTERS[monkey] dummy = _Formatter() _FORMATTERS[monkey] = lambda *options: dummy try: main(args) finally: _FORMATTERS[monkey] = before return dummy def test_w_mising_dist(self): from pkginfo import commandline as MUT def _get_metadata(path_or_module, md_version): self.assertEqual(path_or_module, 'foo') self.assertEqual(md_version, None) return None with _Monkey(MUT, get_metadata=_get_metadata): formatter = self._callFUT(['foo']) self.assertEqual(formatter._called_with, []) self.assertTrue(formatter._finished) def test_w_dist_wo_download_url(self): from pkginfo import commandline as MUT meta = _Meta(download_url=None) def _get_metadata(path_or_module, md_version): self.assertEqual(path_or_module, '/path/to/foo') self.assertEqual(md_version, None) return meta with _Monkey(MUT, get_metadata=_get_metadata): formatter = self._callFUT( ['-d', 'http://example.com', '/path/to/foo']) self.assertEqual(formatter._called_with, [meta]) self.assertTrue(formatter._finished) self.assertEqual(meta.download_url, 'http://example.com/foo') def test_w_dist_w_download_url(self): from pkginfo import commandline as MUT meta = _Meta(download_url='http://example.com/dist/foo') def _get_metadata(path_or_module, md_version): self.assertEqual(path_or_module, '/path/to/foo') self.assertEqual(md_version, None) return meta with _Monkey(MUT, get_metadata=_get_metadata): formatter = self._callFUT( ['-d', 'http://example.com', '/path/to/foo']) self.assertEqual(formatter._called_with, [meta]) self.assertTrue(formatter._finished) self.assertEqual(meta.download_url, 'http://example.com/dist/foo') class _Options(object): def __init__(self, **kw): for k in kw: self.__dict__[k] = kw[k] class _Meta(object): def __init__(self, **kw): for k in kw: self.__dict__[k] = kw[k] def __iter__(self): return iter(sorted(self.__dict__)) class _Monkey(object): # context-manager for replacing module names in the scope of a test. def __init__(self, module, **kw): self.module = module self.to_restore = dict([(key, getattr(module, key)) for key in kw]) for key, value in kw.items(): setattr(module, key, value) def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): for key, value in self.to_restore.items(): setattr(self.module, key, value) class _Formatter(object): _finished = False def __init__(self): self._called_with = [] def __call__(self, meta): self._called_with.append(meta) def finish(self): self._finished = True pkginfo-1.2.1/pkginfo/tests/__init__.py0000644000175000017500000000252412225341570021230 0ustar tseavertseaver00000000000000# requirements def _checkSample(testcase, installed): try: import pkg_resources except ImportError: # no setuptools :( pass else: version = pkg_resources.require('pkginfo')[0].version testcase.assertEqual(installed.version, version) testcase.assertEqual(installed.name, 'pkginfo') testcase.assertEqual(installed.keywords, 'distribution sdist installed metadata' ) testcase.assertEqual(list(installed.supported_platforms), []) def _checkClassifiers(testcase, installed): testcase.assertEqual(list(installed.classifiers), [ 'Intended Audience :: Developers', 'License :: OSI Approved :: Python Software Foundation License', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: System :: Software Distribution', ]) def _defaultMetadataVersion(): import sys if sys.version_info[:2] > (2, 6): return '1.1' return '1.0' pkginfo-1.2.1/pkginfo/tests/silly/0000775000175000017500000000000012451564507020262 5ustar tseavertseaver00000000000000pkginfo-1.2.1/pkginfo/tests/silly/PKG-INFO0000644000175000017500000000005711464573074021361 0ustar tseavertseaver00000000000000Metadata-Version: 1.0 Name: silly Version: 0.1 pkginfo-1.2.1/pkginfo/tests/test_index.py0000644000175000017500000000511412067400744021640 0ustar tseavertseaver00000000000000import unittest class IndexTests(unittest.TestCase): def _getTargetClass(self): from pkginfo.index import Index return Index def _makeOne(self): return self._getTargetClass()() def test_empty(self): index = self._makeOne() self.assertEqual(len(index), 0) self.assertEqual(len(index.keys()), 0) self.assertEqual(len(index.values()), 0) self.assertEqual(len(index.items()), 0) def _makeDummy(self): from pkginfo.distribution import Distribution class DummyDistribution(Distribution): name = 'dummy' version = '1.0' return DummyDistribution() def test___getitem___miss(self): index = self._makeOne() self.assertRaises(KeyError, index.__getitem__, 'nonesuch') def test___setitem___value_not_dist(self): class NotDistribution: name = 'dummy' version = '1.0' dummy = NotDistribution() index = self._makeOne() self.assertRaises(ValueError, index.__setitem__, 'dummy-1.0', dummy) def test___setitem___bad_key(self): index = self._makeOne() dummy = self._makeDummy() self.assertRaises(ValueError, index.__setitem__, 'nonesuch', dummy) def test___setitem___valid_key(self): index = self._makeOne() dummy = self._makeDummy() index['dummy-1.0'] = dummy self.assertTrue(index['dummy-1.0'] is dummy) self.assertEqual(len(index), 1) self.assertEqual(len(index.keys()), 1) self.assertEqual(list(index.keys())[0], 'dummy-1.0') self.assertEqual(len(index.values()), 1) self.assertEqual(list(index.values())[0], dummy) self.assertEqual(len(index.items()), 1) self.assertEqual(list(index.items())[0], ('dummy-1.0', dummy)) def test_add_not_dist(self): index = self._makeOne() class NotDistribution: name = 'dummy' version = '1.0' dummy = NotDistribution() self.assertRaises(ValueError, index.add, dummy) def test_add_valid_dist(self): index = self._makeOne() dummy = self._makeDummy() index.add(dummy) self.assertTrue(index['dummy-1.0'] is dummy) self.assertEqual(len(index), 1) self.assertEqual(len(index.keys()), 1) self.assertEqual(list(index.keys())[0], 'dummy-1.0') self.assertEqual(len(index.values()), 1) self.assertEqual(list(index.values())[0], dummy) self.assertEqual(len(index.items()), 1) self.assertEqual(list(index.items())[0], ('dummy-1.0', dummy)) pkginfo-1.2.1/pkginfo/tests/test_installed.py0000644000175000017500000001303512451560024022504 0ustar tseavertseaver00000000000000import unittest class InstalledTests(unittest.TestCase): def _getTargetClass(self): from pkginfo.installed import Installed return Installed def _makeOne(self, filename=None, metadata_version=None): if metadata_version is not None: return self._getTargetClass()(filename, metadata_version) return self._getTargetClass()(filename) def test_ctor_w_package_no___file__(self): import sys import warnings with warnings.catch_warnings(record=True): installed = self._makeOne(sys) self.assertEqual(installed.package, sys) self.assertEqual(installed.package_name, 'sys') self.assertEqual(installed.metadata_version, None) def test_ctor_w_package(self): import pkginfo from pkginfo.tests import _checkSample from pkginfo.tests import _defaultMetadataVersion EXPECTED = _defaultMetadataVersion() installed = self._makeOne(pkginfo) self.assertEqual(installed.package, pkginfo) self.assertEqual(installed.package_name, 'pkginfo') self.assertEqual(installed.metadata_version, EXPECTED) _checkSample(self, installed) def test_ctor_w_no___package___falls_back_to___name__(self): import sys import wsgiref import warnings with warnings.catch_warnings(record=True): installed = self._makeOne(wsgiref) self.assertEqual(installed.package, wsgiref) self.assertEqual(installed.package_name, 'wsgiref') if sys.version_info[:2] >= (3, 3): self.assertEqual(installed.metadata_version, None) else: self.assertEqual(installed.metadata_version, '1.0') def test_ctor_w_package_no_PKG_INFO(self): import sys import types import warnings with warnings.catch_warnings(record=True): installed = self._makeOne(types) self.assertEqual(installed.package, types) self.assertEqual(installed.package_name, 'types') if sys.version_info[:2] >= (3, 3): self.assertEqual(installed.metadata_version, '1.1') else: self.assertEqual(installed.metadata_version, None) def test_ctor_w_package_and_metadata_version(self): import pkginfo from pkginfo.tests import _checkSample installed = self._makeOne(pkginfo, metadata_version='1.2') self.assertEqual(installed.metadata_version, '1.2') self.assertEqual(installed.package.__name__, 'pkginfo') _checkSample(self, installed) def test_ctor_w_name(self): import pkginfo from pkginfo.tests import _checkSample from pkginfo.tests import _defaultMetadataVersion EXPECTED = _defaultMetadataVersion() installed = self._makeOne('pkginfo') self.assertEqual(installed.metadata_version, EXPECTED) self.assertEqual(installed.package, pkginfo) self.assertEqual(installed.package_name, 'pkginfo') _checkSample(self, installed) def test_ctor_w_name_and_metadata_version(self): import pkginfo from pkginfo.tests import _checkSample installed = self._makeOne('pkginfo', metadata_version='1.2') self.assertEqual(installed.metadata_version, '1.2') self.assertEqual(installed.package, pkginfo) self.assertEqual(installed.package_name, 'pkginfo') _checkSample(self, installed) def test_ctor_w_invalid_name(self): import warnings with warnings.catch_warnings(record=True): installed = self._makeOne('nonesuch') self.assertEqual(installed.package, None) self.assertEqual(installed.package_name, 'nonesuch') self.assertEqual(installed.metadata_version, None) def test_ctor_w_egg_info_as_file(self): import pkginfo.tests.funny installed = self._makeOne('pkginfo.tests.funny') self.assertEqual(installed.metadata_version, '1.0') self.assertEqual(installed.package, pkginfo.tests.funny) self.assertEqual(installed.package_name, 'pkginfo.tests.funny') def test_namespaced_pkg_installed_via_setuptools(self): import os import sys where, _ = os.path.split(__file__) wonky = os.path.join(where, 'wonky') oldpath = sys.path[:] try: sys.path.append(wonky) import namespaced.wonky installed = self._makeOne('namespaced.wonky') self.assertEqual(installed.metadata_version, '1.0') self.assertEqual(installed.package, namespaced.wonky) self.assertEqual(installed.package_name, 'namespaced.wonky') finally: sys.path[:] = oldpath sys.modules.pop('namespaced.wonky', None) sys.modules.pop('namespaced', None) def test_namespaced_pkg_installed_via_pth(self): # E.g., installed by a Linux distro import os import sys where, _ = os.path.split(__file__) manky = os.path.join(where, 'manky') oldpath = sys.path[:] try: sys.path.append(manky) import namespaced.manky installed = self._makeOne('namespaced.manky') self.assertEqual(installed.metadata_version, '1.0') self.assertEqual(installed.package, namespaced.manky) self.assertEqual(installed.package_name, 'namespaced.manky') finally: sys.path[:] = oldpath sys.modules.pop('namespaced.manky', None) sys.modules.pop('namespaced', None) pkginfo-1.2.1/pkginfo/tests/test_wheel.py0000664000175000017500000000457012245465112021642 0ustar tseavertseaver00000000000000import unittest class WheelTests(unittest.TestCase): def _getTargetClass(self): from pkginfo.wheel import Wheel return Wheel def _makeOne(self, filename=None, metadata_version=None): if metadata_version is not None: return self._getTargetClass()(filename, metadata_version) return self._getTargetClass()(filename) def _checkSample(self, wheel, filename): self.assertEqual(wheel.filename, filename) self.assertEqual(wheel.name, 'mypackage') self.assertEqual(wheel.version, '0.1') self.assertEqual(wheel.keywords, None) def _checkClassifiers(self, wheel): self.assertEqual(list(wheel.classifiers), ['Development Status :: 4 - Beta', 'Environment :: Console (Text Based)', ]) self.assertEqual(list(wheel.supported_platforms), []) def test_ctor_w_bogus_filename(self): import os d, _ = os.path.split(__file__) filename = '%s/../../docs/examples/nonesuch-0.1-any.whl' % d self.assertRaises(ValueError, self._makeOne, filename) def test_ctor_w_non_wheel(self): import os d, _ = os.path.split(__file__) filename = '%s/../../docs/examples/mypackage-0.1.zip' % d self.assertRaises(ValueError, self._makeOne, filename) def test_ctor_wo_dist_info(self): import os d, _ = os.path.split(__file__) filename = '%s/../../docs/examples/nodistinfo-0.1-any.whl' % d self.assertRaises(ValueError, self._makeOne, filename) def test_ctor_w_valid_wheel(self): import os d, _ = os.path.split(__file__) filename = ('%s/../../docs/examples/' 'mypackage-0.1-cp26-none-linux_x86_64.whl') % d wheel = self._makeOne(filename) self.assertEqual(wheel.metadata_version, '2.0') self._checkSample(wheel, filename) self._checkClassifiers(wheel) def test_ctor_w_valid_wheel_and_metadata_version(self): import os d, _ = os.path.split(__file__) filename = ('%s/../../docs/examples/' 'mypackage-0.1-cp26-none-linux_x86_64.whl') % d wheel = self._makeOne(filename, metadata_version='1.1') self.assertEqual(wheel.metadata_version, '1.1') self._checkSample(wheel, filename) self._checkClassifiers(wheel) pkginfo-1.2.1/pkginfo/tests/funny/0000775000175000017500000000000012451564507020265 5ustar tseavertseaver00000000000000pkginfo-1.2.1/pkginfo/tests/funny/__init__.py0000644000175000017500000000010411464571503022364 0ustar tseavertseaver00000000000000# sample installed package w/ .egg-info file. __package__ = 'funny' pkginfo-1.2.1/pkginfo/tests/funny/funny.egg-info0000644000175000017500000000005711464570605023040 0ustar tseavertseaver00000000000000Metadata-Version: 1.0 Name: funny Version: 0.1 pkginfo-1.2.1/pkginfo/tests/test_distribution.py0000644000175000017500000003715712225346062023262 0ustar tseavertseaver00000000000000import unittest class DistributionTests(unittest.TestCase): def _getTargetClass(self): from pkginfo.distribution import Distribution return Distribution def _makeOne(self, metadata_version='1.0'): dist = self._getTargetClass()() if metadata_version is not None: dist.metadata_version = metadata_version return dist def test_ctor_defaults(self): sdist = self._makeOne(None) self.assertEqual(sdist.metadata_version, None) self.assertEqual(sdist.name, None) self.assertEqual(sdist.version, None) self.assertEqual(sdist.platforms, ()) self.assertEqual(sdist.supported_platforms, ()) self.assertEqual(sdist.summary, None) self.assertEqual(sdist.description, None) self.assertEqual(sdist.keywords, None) self.assertEqual(sdist.home_page, None) self.assertEqual(sdist.download_url, None) self.assertEqual(sdist.author, None) self.assertEqual(sdist.author_email, None) self.assertEqual(sdist.license, None) self.assertEqual(sdist.classifiers, ()) self.assertEqual(sdist.requires, ()) self.assertEqual(sdist.provides, ()) self.assertEqual(sdist.obsoletes, ()) self.assertEqual(sdist.maintainer, None) self.assertEqual(sdist.maintainer_email, None) self.assertEqual(sdist.requires_python, None) self.assertEqual(sdist.requires_external, ()) self.assertEqual(sdist.requires_dist, ()) self.assertEqual(sdist.provides_dist, ()) self.assertEqual(sdist.obsoletes_dist, ()) self.assertEqual(sdist.project_urls, ()) def test_extractMetadata_raises_NotImplementedError(self): # 'extractMetadata' calls 'read', which subclasses must override. dist = self._makeOne(None) self.assertRaises(NotImplementedError, dist.extractMetadata) def test_read_raises_NotImplementedError(self): # Subclasses must override 'read'. dist = self._makeOne(None) self.assertRaises(NotImplementedError, dist.read) def test_parse_Metadata_Version_1_0(self): from pkginfo.distribution import HEADER_ATTRS_1_0 dist = self._makeOne(None) dist.parse('Metadata-Version: 1.0') self.assertEqual(dist.metadata_version, '1.0') self.assertEqual(list(dist), [x[1] for x in HEADER_ATTRS_1_0]) def test_parse_Metadata_Version_1_1(self): from pkginfo.distribution import HEADER_ATTRS_1_1 dist = self._makeOne(None) dist.parse('Metadata-Version: 1.1') self.assertEqual(dist.metadata_version, '1.1') self.assertEqual(list(dist), [x[1] for x in HEADER_ATTRS_1_1]) def test_parse_Metadata_Version_1_2(self): from pkginfo.distribution import HEADER_ATTRS_1_2 dist = self._makeOne(None) dist.parse('Metadata-Version: 1.2') self.assertEqual(dist.metadata_version, '1.2') self.assertEqual(list(dist), [x[1] for x in HEADER_ATTRS_1_2]) def test_parse_Metadata_Version_unknown(self): dist = self._makeOne(None) dist.parse('Metadata-Version: 1.3') self.assertEqual(dist.metadata_version, '1.3') self.assertEqual(list(dist), []) def test_parse_Metadata_Version_override(self): dist = self._makeOne('1.2') dist.parse('Metadata-Version: 1.0') self.assertEqual(dist.metadata_version, '1.2') def test_parse_Name(self): dist = self._makeOne() dist.parse('Name: foobar') self.assertEqual(dist.name, 'foobar') def test_parse_Version(self): dist = self._makeOne() dist.parse('Version: 2.1.3b5') self.assertEqual(dist.version, '2.1.3b5') def test_parse_Platform_single(self): dist = self._makeOne() dist.parse('Platform: Plan9') self.assertEqual(list(dist.platforms), ['Plan9']) def test_parse_Platform_multiple(self): dist = self._makeOne() dist.parse('Platform: Plan9\nPlatform: AIX') self.assertEqual(list(dist.platforms), ['Plan9', 'AIX']) def test_parse_Supported_Platform_single(self): dist = self._makeOne() dist.parse('Supported-Platform: Plan9') self.assertEqual(list(dist.supported_platforms), ['Plan9']) def test_parse_Supported_Platform_multiple(self): dist = self._makeOne() dist.parse('Supported-Platform: i386-win32\n' 'Supported-Platform: RedHat 7.2') self.assertEqual(list(dist.supported_platforms), ['i386-win32', 'RedHat 7.2']) def test_parse_Summary(self): dist = self._makeOne() dist.parse('Summary: Package for foo') self.assertEqual(dist.summary, 'Package for foo') def test_parse_Description(self): dist = self._makeOne() dist.parse('Description: This package enables integration with ' 'foo servers.') self.assertEqual(dist.description, 'This package enables integration with ' 'foo servers.') def test_parse_Description_multiline(self): dist = self._makeOne() dist.parse('Description: This package enables integration with\n' ' foo servers.') self.assertEqual(dist.description, 'This package enables integration with\n' 'foo servers.') def test_parse_Keywords(self): dist = self._makeOne() dist.parse('Keywords: bar foo qux') self.assertEqual(dist.keywords, 'bar foo qux') def test_parse_Home_page(self): dist = self._makeOne() dist.parse('Home-page: http://example.com/package') self.assertEqual(dist.home_page, 'http://example.com/package') def test_parse_Author(self): dist = self._makeOne() dist.parse('Author: J. Phredd Bloggs') self.assertEqual(dist.author, 'J. Phredd Bloggs') def test_parse_Author_Email(self): dist = self._makeOne() dist.parse('Author-email: phreddy@example.com') self.assertEqual(dist.author_email, 'phreddy@example.com') def test_parse_License(self): dist = self._makeOne() dist.parse('License: Poetic') self.assertEqual(dist.license, 'Poetic') # Metadata version 1.1, defined in PEP 314. def test_parse_Classifier_single(self): dist = self._makeOne('1.1') dist.parse('Classifier: Some :: Silly Thing') self.assertEqual(list(dist.classifiers), ['Some :: Silly Thing']) def test_parse_Classifier_multiple(self): dist = self._makeOne('1.1') dist.parse('Classifier: Some :: Silly Thing\n' 'Classifier: Or :: Other') self.assertEqual(list(dist.classifiers), ['Some :: Silly Thing', 'Or :: Other']) def test_parse_Download_URL(self): dist = self._makeOne('1.1') dist.parse('Download-URL: ' 'http://example.com/package/mypackage-0.1.zip') self.assertEqual(dist.download_url, 'http://example.com/package/mypackage-0.1.zip') def test_parse_Requires_single_wo_version(self): dist = self._makeOne('1.1') dist.parse('Requires: SpanishInquisition') self.assertEqual(list(dist.requires), ['SpanishInquisition']) def test_parse_Requires_single_w_version(self): dist = self._makeOne('1.1') dist.parse('Requires: SpanishInquisition (>=1.3)') self.assertEqual(list(dist.requires), ['SpanishInquisition (>=1.3)']) def test_parse_Requires_multiple(self): dist = self._makeOne('1.1') dist.parse('Requires: SpanishInquisition\n' 'Requires: SillyWalks (1.4)\n' 'Requires: kniggits (>=2.3,<3.0)') self.assertEqual(list(dist.requires), ['SpanishInquisition', 'SillyWalks (1.4)', 'kniggits (>=2.3,<3.0)', ]) def test_parse_Provides_single_wo_version(self): dist = self._makeOne('1.1') dist.parse('Provides: SillyWalks') self.assertEqual(list(dist.provides), ['SillyWalks']) def test_parse_Provides_single_w_version(self): dist = self._makeOne('1.1') dist.parse('Provides: SillyWalks (1.4)') self.assertEqual(list(dist.provides), ['SillyWalks (1.4)']) def test_parse_Provides_multiple(self): dist = self._makeOne('1.1') dist.parse('Provides: SillyWalks\n' 'Provides: DeadlyJoke (3.1.4)') self.assertEqual(list(dist.provides), ['SillyWalks', 'DeadlyJoke (3.1.4)', ]) def test_parse_Obsoletes_single_no_version(self): dist = self._makeOne('1.1') dist.parse('Obsoletes: SillyWalks') self.assertEqual(list(dist.obsoletes), ['SillyWalks']) def test_parse_Obsoletes_single_w_version(self): dist = self._makeOne('1.1') dist.parse('Obsoletes: SillyWalks (<=1.3)') self.assertEqual(list(dist.obsoletes), ['SillyWalks (<=1.3)']) def test_parse_Obsoletes_multiple(self): dist = self._makeOne('1.1') dist.parse('Obsoletes: kniggits\n' 'Obsoletes: SillyWalks (<=2.0)') self.assertEqual(list(dist.obsoletes), ['kniggits', 'SillyWalks (<=2.0)', ]) # Metadata version 1.2, defined in PEP 345. def test_parse_Maintainer(self): dist = self._makeOne(metadata_version='1.2') dist.parse('Maintainer: J. Phredd Bloggs') self.assertEqual(dist.maintainer, 'J. Phredd Bloggs') def test_parse_Maintainer_Email(self): dist = self._makeOne(metadata_version='1.2') dist.parse('Maintainer-email: phreddy@example.com') self.assertEqual(dist.maintainer_email, 'phreddy@example.com') def test_parse_Requires_Python_single_spec(self): dist = self._makeOne('1.2') dist.parse('Requires-Python: >2.4') self.assertEqual(dist.requires_python, '>2.4') def test_parse_Requires_External_single_wo_version(self): dist = self._makeOne('1.2') dist.parse('Requires-External: libfoo') self.assertEqual(list(dist.requires_external), ['libfoo']) def test_parse_Requires_External_single_w_version(self): dist = self._makeOne('1.2') dist.parse('Requires-External: libfoo (>=1.3)') self.assertEqual(list(dist.requires_external), ['libfoo (>=1.3)']) def test_parse_Requires_External_multiple(self): dist = self._makeOne('1.2') dist.parse('Requires-External: libfoo\n' 'Requires-External: libbar (1.4)\n' 'Requires-External: libbaz (>=2.3,<3.0)') self.assertEqual(list(dist.requires_external), ['libfoo', 'libbar (1.4)', 'libbaz (>=2.3,<3.0)', ]) def test_parse_Requires_Dist_single_wo_version(self): dist = self._makeOne('1.2') dist.parse('Requires-Dist: SpanishInquisition') self.assertEqual(list(dist.requires_dist), ['SpanishInquisition']) def test_parse_Requires_Dist_single_w_version(self): dist = self._makeOne('1.2') dist.parse('Requires-Dist: SpanishInquisition (>=1.3)') self.assertEqual(list(dist.requires_dist), ['SpanishInquisition (>=1.3)']) def test_parse_Requires_Dist_single_w_env_marker(self): dist = self._makeOne('1.2') dist.parse("Requires-Dist: SpanishInquisition; " "python_version == '1.4'") self.assertEqual(list(dist.requires_dist), ["SpanishInquisition; python_version == '1.4'"]) def test_parse_Requires_Dist_multiple(self): dist = self._makeOne('1.2') dist.parse("Requires-Dist: SpanishInquisition\n" "Requires-Dist: SillyWalks; python_version == '1.4'\n" "Requires-Dist: kniggits (>=2.3,<3.0)") self.assertEqual(list(dist.requires_dist), ["SpanishInquisition", "SillyWalks; python_version == '1.4'", "kniggits (>=2.3,<3.0)", ]) def test_parse_Provides_Dist_single_wo_version(self): dist = self._makeOne('1.2') dist.parse('Provides-Dist: SillyWalks') self.assertEqual(list(dist.provides_dist), ['SillyWalks']) def test_parse_Provides_Dist_single_w_version(self): dist = self._makeOne('1.2') dist.parse('Provides-Dist: SillyWalks (1.4)') self.assertEqual(list(dist.provides_dist), ['SillyWalks (1.4)']) def test_parse_Provides_Dist_single_w_env_marker(self): dist = self._makeOne('1.2') dist.parse("Provides-Dist: SillyWalks; sys.platform == 'os2'") self.assertEqual(list(dist.provides_dist), ["SillyWalks; sys.platform == 'os2'"]) def test_parse_Provides_Dist_multiple(self): dist = self._makeOne('1.2') dist.parse("Provides-Dist: SillyWalks\n" "Provides-Dist: SpanishInquisition; sys.platform == 'os2'\n" "Provides-Dist: DeadlyJoke (3.1.4)") self.assertEqual(list(dist.provides_dist), ["SillyWalks", "SpanishInquisition; sys.platform == 'os2'", "DeadlyJoke (3.1.4)", ]) def test_parse_Obsoletes_Dist_single_no_version(self): dist = self._makeOne('1.2') dist.parse('Obsoletes-Dist: SillyWalks') self.assertEqual(list(dist.obsoletes_dist), ['SillyWalks']) def test_parse_Obsoletes_Dist_single_w_version(self): dist = self._makeOne('1.2') dist.parse('Obsoletes-Dist: SillyWalks (<=1.3)') self.assertEqual(list(dist.obsoletes_dist), ['SillyWalks (<=1.3)']) def test_parse_Obsoletes_Dist_single_w_env_marker(self): dist = self._makeOne('1.2') dist.parse("Obsoletes-Dist: SillyWalks; sys.platform == 'os2'") self.assertEqual(list(dist.obsoletes_dist), ["SillyWalks; sys.platform == 'os2'"]) def test_parse_Obsoletes_Dist_multiple(self): dist = self._makeOne('1.2') dist.parse("Obsoletes-Dist: kniggits\n" "Obsoletes-Dist: SillyWalks; sys.platform == 'os2'\n" "Obsoletes-Dist: DeadlyJoke (<=2.0)\n" ) self.assertEqual(list(dist.obsoletes_dist), ["kniggits", "SillyWalks; sys.platform == 'os2'", "DeadlyJoke (<=2.0)", ]) def test_parse_Project_URL_single_no_version(self): dist = self._makeOne('1.2') dist.parse('Project-URL: Bug tracker, http://bugs.example.com/grail') self.assertEqual(list(dist.project_urls), ['Bug tracker, http://bugs.example.com/grail']) def test_parse_Project_URL_multiple(self): dist = self._makeOne('1.2') dist.parse('Project-URL: Bug tracker, http://bugs.example.com/grail\n' 'Project-URL: Repository, http://svn.example.com/grail') self.assertEqual(list(dist.project_urls), ['Bug tracker, http://bugs.example.com/grail', 'Repository, http://svn.example.com/grail', ]) def test_parse_given_unicode(self): from pkginfo._compat import u dist = self._makeOne() dist.parse(u('Metadata-Version: 1.0\nName: lp722928_c3')) # no raise pkginfo-1.2.1/pkginfo/tests/manky/0000775000175000017500000000000012451564507020245 5ustar tseavertseaver00000000000000pkginfo-1.2.1/pkginfo/tests/manky/namespaced.manky-0.1.egg-info/0000775000175000017500000000000012451564507025451 5ustar tseavertseaver00000000000000pkginfo-1.2.1/pkginfo/tests/manky/namespaced.manky-0.1.egg-info/PKG-INFO0000644000175000017500000000005511724736225026544 0ustar tseavertseaver00000000000000Metadata-Version: 1.0 Name: namespaced.wonky pkginfo-1.2.1/pkginfo/tests/manky/NOT-A-PACKAGE.txt0000644000175000017500000000022011724734771022651 0ustar tseavertseaver00000000000000THIS IS NOT A PYTHON PACKAGE!!!! It is meant to be added to sys.path for testing introspection of namespace packages installed via setuptools. pkginfo-1.2.1/pkginfo/tests/manky/namespaced/0000775000175000017500000000000012451564507022345 5ustar tseavertseaver00000000000000pkginfo-1.2.1/pkginfo/tests/manky/namespaced/__init__.py0000644000175000017500000000031011724735325024446 0ustar tseavertseaver00000000000000# this is a namespace package try: import pkg_resources pkg_resources.declare_namespace(__name__) except ImportError: import pkgutil __path__ = pkgutil.extend_path(__path__, __name__) pkginfo-1.2.1/pkginfo/tests/manky/namespaced/manky/0000775000175000017500000000000012451564507023464 5ustar tseavertseaver00000000000000pkginfo-1.2.1/pkginfo/tests/manky/namespaced/manky/__init__.py0000644000175000017500000000006311724735325025572 0ustar tseavertseaver00000000000000# Dummy package inside the 'namespaced' namespace. pkginfo-1.2.1/pkginfo/tests/test_utils.py0000644000175000017500000001526312245466311021677 0ustar tseavertseaver00000000000000import unittest class Test_get_metadata(unittest.TestCase): def _callFUT(self, path, metadata_version=None): from pkginfo.utils import get_metadata if metadata_version is not None: return get_metadata(path, metadata_version) return get_metadata(path) def _checkMyPackage(self, dist, filename): self.assertEqual(dist.filename, filename) self.assertEqual(dist.name, 'mypackage') self.assertEqual(dist.version, '0.1') self.assertEqual(dist.keywords, None) self.assertEqual(list(dist.supported_platforms), []) def _checkClassifiers(self, dist): self.assertEqual(list(dist.classifiers), ['Development Status :: 4 - Beta', 'Environment :: Console (Text Based)', ]) def test_w_gztar(self): import os d, _ = os.path.split(__file__) filename = '%s/../../docs/examples/mypackage-0.1.tar.gz' % d dist = self._callFUT(filename) self.assertEqual(dist.metadata_version, '1.0') self._checkMyPackage(dist, filename) def test_w_gztar_and_metadata_version(self): import os d, _ = os.path.split(__file__) filename = '%s/../../docs/examples/mypackage-0.1.tar.gz' % d dist = self._callFUT(filename, metadata_version='1.1') self.assertEqual(dist.metadata_version, '1.1') self._checkMyPackage(dist, filename) self._checkClassifiers(dist) def test_w_bztar(self): import os d, _ = os.path.split(__file__) filename = '%s/../../docs/examples/mypackage-0.1.tar.bz2' % d dist = self._callFUT(filename) self.assertEqual(dist.metadata_version, '1.0') self._checkMyPackage(dist, filename) def test_w_bztar_and_metadata_version(self): import os d, _ = os.path.split(__file__) filename = '%s/../../docs/examples/mypackage-0.1.tar.bz2' % d dist = self._callFUT(filename, metadata_version='1.1') self.assertEqual(dist.metadata_version, '1.1') self._checkMyPackage(dist, filename) self._checkClassifiers(dist) def test_w_zip(self): import os d, _ = os.path.split(__file__) filename = '%s/../../docs/examples/mypackage-0.1.zip' % d dist = self._callFUT(filename) self.assertEqual(dist.metadata_version, '1.0') self._checkMyPackage(dist, filename) def test_w_zip_and_metadata_version(self): import os d, _ = os.path.split(__file__) filename = '%s/../../docs/examples/mypackage-0.1.zip' % d dist = self._callFUT(filename, metadata_version='1.1') self.assertEqual(dist.metadata_version, '1.1') self._checkMyPackage(dist, filename) self._checkClassifiers(dist) def test_w_egg(self): import os d, _ = os.path.split(__file__) filename = '%s/../../docs/examples/mypackage-0.1-py2.6.egg' % d dist = self._callFUT(filename) self.assertEqual(dist.metadata_version, '1.0') self._checkMyPackage(dist, filename) def test_w_egg_and_metadata_version(self): import os d, _ = os.path.split(__file__) filename = '%s/../../docs/examples/mypackage-0.1-py2.6.egg' % d dist = self._callFUT(filename, metadata_version='1.1') self.assertEqual(dist.metadata_version, '1.1') self._checkMyPackage(dist, filename) self._checkClassifiers(dist) def test_w_wheel(self): import os d, _ = os.path.split(__file__) filename = ('%s/../../docs/examples/' 'mypackage-0.1-cp26-none-linux_x86_64.whl') % d dist = self._callFUT(filename) self.assertEqual(dist.metadata_version, '2.0') self._checkMyPackage(dist, filename) def test_w_wheel_and_metadata_version(self): import os d, _ = os.path.split(__file__) filename = ('%s/../../docs/examples/' 'mypackage-0.1-cp26-none-linux_x86_64.whl') % d dist = self._callFUT(filename, metadata_version='1.1') self.assertEqual(dist.metadata_version, '1.1') self._checkMyPackage(dist, filename) self._checkClassifiers(dist) def test_w_module(self): from pkginfo.tests import _defaultMetadataVersion EXPECTED = _defaultMetadataVersion() import pkginfo from pkginfo.tests import _checkSample dist = self._callFUT(pkginfo) self.assertEqual(dist.metadata_version, EXPECTED) _checkSample(self, dist) def test_w_module_and_metadata_version(self): import pkginfo from pkginfo.tests import _checkSample from pkginfo.tests import _checkClassifiers dist = self._callFUT(pkginfo, metadata_version='1.2') self.assertEqual(dist.metadata_version, '1.2') _checkSample(self, dist) _checkClassifiers(self, dist) def test_w_package_name(self): from pkginfo.tests import _defaultMetadataVersion EXPECTED = _defaultMetadataVersion() from pkginfo.tests import _checkSample dist = self._callFUT('pkginfo') self.assertEqual(dist.metadata_version, EXPECTED) _checkSample(self, dist) def test_w_package_name_and_metadata_version(self): from pkginfo.tests import _checkSample from pkginfo.tests import _checkClassifiers dist = self._callFUT('pkginfo', metadata_version='1.2') self.assertEqual(dist.metadata_version, '1.2') _checkSample(self, dist) _checkClassifiers(self, dist) def test_w_directory_no_EGG_INFO(self): import os import warnings dir, name = os.path.split(__file__) subdir = os.path.join(dir, 'funny') old_filters = warnings.filters[:] warnings.filterwarnings('ignore') try: dist = self._callFUT(subdir) self.assertEqual(dist.path, subdir) self.assertEqual(dist.name, None) self.assertEqual(dist.version, None) finally: warnings.filters[:] = old_filters def test_w_directory(self): import os dir, name = os.path.split(__file__) subdir = os.path.join(dir, 'silly') dist = self._callFUT(subdir) self.assertEqual(dist.metadata_version, '1.0') self.assertEqual(dist.name, 'silly') self.assertEqual(dist.version, '0.1') def test_w_directory_and_metadata_version(self): import os dir, name = os.path.split(__file__) subdir = os.path.join(dir, 'silly') dist = self._callFUT(subdir, metadata_version='1.2') self.assertEqual(dist.metadata_version, '1.2') self.assertEqual(dist.name, 'silly') self.assertEqual(dist.version, '0.1') pkginfo-1.2.1/pkginfo/tests/test_develop.py0000644000175000017500000000225212141477331022166 0ustar tseavertseaver00000000000000import unittest class DevelopTests(unittest.TestCase): def _getTargetClass(self): from pkginfo.develop import Develop return Develop def _makeOne(self, dirname=None): return self._getTargetClass()(dirname) def test_ctor_w_path(self): from pkginfo.tests import _checkSample develop = self._makeOne('.') _checkSample(self, develop) def test_ctor_w_path_nested_egg_info(self): import os dir, name = os.path.split(__file__) subdir = os.path.join(dir, 'sneaky') develop = self._makeOne(subdir) self.assertEqual(develop.metadata_version, '1.0') self.assertEqual(develop.name, 'namespaced.sneaky') self.assertEqual(develop.version, '0.1') def test_ctor_w_invalid_path(self): import warnings old_filters = warnings.filters[:] warnings.filterwarnings('ignore') try: develop = self._makeOne('/nonesuch') self.assertEqual(develop.metadata_version, None) self.assertEqual(develop.name, None) self.assertEqual(develop.version, None) finally: warnings.filters[:] = old_filters pkginfo-1.2.1/pkginfo/tests/wonky/0000775000175000017500000000000012451564507020275 5ustar tseavertseaver00000000000000pkginfo-1.2.1/pkginfo/tests/wonky/EGG-INFO/0000775000175000017500000000000012451564507021430 5ustar tseavertseaver00000000000000pkginfo-1.2.1/pkginfo/tests/wonky/EGG-INFO/PKG-INFO0000644000175000017500000000005511724736166022527 0ustar tseavertseaver00000000000000Metadata-Version: 1.0 Name: namespaced.wonky pkginfo-1.2.1/pkginfo/tests/wonky/NOT-A-PACKAGE.txt0000644000175000017500000000022011724732261022671 0ustar tseavertseaver00000000000000THIS IS NOT A PYTHON PACKAGE!!!! It is meant to be added to sys.path for testing introspection of namespace packages installed via setuptools. pkginfo-1.2.1/pkginfo/tests/wonky/namespaced/0000775000175000017500000000000012451564507022375 5ustar tseavertseaver00000000000000pkginfo-1.2.1/pkginfo/tests/wonky/namespaced/__init__.py0000644000175000017500000000031011724732334024473 0ustar tseavertseaver00000000000000# this is a namespace package try: import pkg_resources pkg_resources.declare_namespace(__name__) except ImportError: import pkgutil __path__ = pkgutil.extend_path(__path__, __name__) pkginfo-1.2.1/pkginfo/tests/wonky/namespaced/wonky/0000775000175000017500000000000012451564507023544 5ustar tseavertseaver00000000000000pkginfo-1.2.1/pkginfo/tests/wonky/namespaced/wonky/__init__.py0000644000175000017500000000006311724732417025651 0ustar tseavertseaver00000000000000# Dummy package inside the 'namespaced' namespace. pkginfo-1.2.1/pkginfo/tests/test_sdist.py0000644000175000017500000001155312141471267021664 0ustar tseavertseaver00000000000000import shutil import tempfile import unittest class SDistTests(unittest.TestCase): def _getTargetClass(self): from pkginfo.sdist import SDist return SDist def _makeOne(self, filename=None, metadata_version=None): if metadata_version is not None: return self._getTargetClass()(filename, metadata_version) return self._getTargetClass()(filename) def _checkSample(self, sdist, filename): self.assertEqual(sdist.filename, filename) self.assertEqual(sdist.name, 'mypackage') self.assertEqual(sdist.version, '0.1') self.assertEqual(sdist.keywords, None) self.assertEqual(list(sdist.supported_platforms), []) def _checkClassifiers(self, sdist): self.assertEqual(list(sdist.classifiers), ['Development Status :: 4 - Beta', 'Environment :: Console (Text Based)', ]) def test_ctor_w_invalid_filename(self): import os d, _ = os.path.split(__file__) filename = '%s/../../docs/examples/nonesuch-0.1.tar.gz' % d self.assertRaises(ValueError, self._makeOne, filename) def test_ctor_wo_PKG_INFO(self): import os d, _ = os.path.split(__file__) filename = '%s/../../docs/examples/nopkginfo-0.1.zip' % d self.assertRaises(ValueError, self._makeOne, filename) def test_ctor_w_gztar(self): import os d, _ = os.path.split(__file__) filename = '%s/../../docs/examples/mypackage-0.1.tar.gz' % d sdist = self._makeOne(filename) self.assertEqual(sdist.metadata_version, '1.0') self._checkSample(sdist, filename) def test_ctor_w_gztar_and_metadata_version(self): import os d, _ = os.path.split(__file__) filename = '%s/../../docs/examples/mypackage-0.1.tar.gz' % d sdist = self._makeOne(filename, metadata_version='1.1') self._checkSample(sdist, filename) self.assertEqual(sdist.metadata_version, '1.1') self._checkClassifiers(sdist) def test_ctor_w_bztar(self): import os d, _ = os.path.split(__file__) filename = '%s/../../docs/examples/mypackage-0.1.tar.bz2' % d sdist = self._makeOne(filename) self.assertEqual(sdist.metadata_version, '1.0') self._checkSample(sdist, filename) def test_ctor_w_bztar_and_metadata_version(self): import os d, _ = os.path.split(__file__) filename = '%s/../../docs/examples/mypackage-0.1.tar.bz2' % d sdist = self._makeOne(filename, metadata_version='1.1') self.assertEqual(sdist.metadata_version, '1.1') self._checkSample(sdist, filename) self._checkClassifiers(sdist) def test_ctor_w_zip(self): import os d, _ = os.path.split(__file__) filename = '%s/../../docs/examples/mypackage-0.1.zip' % d sdist = self._makeOne(filename) self.assertEqual(sdist.metadata_version, '1.0') self._checkSample(sdist, filename) def test_ctor_w_zip_and_metadata_version(self): import os d, _ = os.path.split(__file__) filename = '%s/../../docs/examples/mypackage-0.1.zip' % d sdist = self._makeOne(filename, metadata_version='1.1') self.assertEqual(sdist.metadata_version, '1.1') self._checkSample(sdist, filename) self._checkClassifiers(sdist) class UnpackedMixin(object): def setUp(self): super(UnpackedMixin, self).setUp() self.__tmpdir = tempfile.mkdtemp() def tearDown(self): shutil.rmtree(self.__tmpdir) super(UnpackedMixin, self).tearDown() def _getTargetClass(self): from pkginfo.sdist import UnpackedSDist return UnpackedSDist def _getTopDirectory(self): import os topnames = os.listdir(self.__tmpdir) if len(topnames) == 1: return os.path.join(self.__tmpdir, topnames[0]) else: return self.__tmpdir def _getLoadFilename(self): return self._getTopDirectory() def _makeOne(self, filename=None, metadata_version=None): archive, _, _ = self._getTargetClass()._get_archive(filename) try: archive.extractall(self.__tmpdir) finally: archive.close() load_filename = self._getLoadFilename() if metadata_version is not None: return self._getTargetClass()(load_filename, metadata_version) return self._getTargetClass()(load_filename) def _checkSample(self, sdist, filename): filename = self._getTopDirectory() super(UnpackedMixin, self)._checkSample(sdist, filename) class UnpackedSDistGivenDirectoryTests(UnpackedMixin, SDistTests): pass class UnpackedSDistGivenFileSDistTests(UnpackedMixin, SDistTests): def _getLoadFilename(self): import os return os.path.join(self._getTopDirectory(), 'setup.py') pkginfo-1.2.1/pkginfo/tests/test_bdist.py0000644000175000017500000000434711464567536021662 0ustar tseavertseaver00000000000000import unittest class BDistTests(unittest.TestCase): def _getTargetClass(self): from pkginfo.bdist import BDist return BDist def _makeOne(self, filename=None, metadata_version=None): if metadata_version is not None: return self._getTargetClass()(filename, metadata_version) return self._getTargetClass()(filename) def _checkSample(self, bdist, filename): self.assertEqual(bdist.filename, filename) self.assertEqual(bdist.name, 'mypackage') self.assertEqual(bdist.version, '0.1') self.assertEqual(bdist.keywords, None) def _checkClassifiers(self, bdist): self.assertEqual(list(bdist.classifiers), ['Development Status :: 4 - Beta', 'Environment :: Console (Text Based)', ]) self.assertEqual(list(bdist.supported_platforms), []) def test_ctor_w_bogus_filename(self): import os d, _ = os.path.split(__file__) filename = '%s/../../docs/examples/nonesuch-0.1-py2.6.egg' % d self.assertRaises(ValueError, self._makeOne, filename) def test_ctor_w_non_egg(self): import os d, _ = os.path.split(__file__) filename = '%s/../../docs/examples/mypackage-0.1.zip' % d self.assertRaises(ValueError, self._makeOne, filename) def test_ctor_wo_PKG_INFO(self): import os d, _ = os.path.split(__file__) filename = '%s/../../docs/examples/nopkginfo-0.1.egg' % d self.assertRaises(ValueError, self._makeOne, filename) def test_ctor_w_egg(self): import os d, _ = os.path.split(__file__) filename = '%s/../../docs/examples/mypackage-0.1-py2.6.egg' % d bdist = self._makeOne(filename) self.assertEqual(bdist.metadata_version, '1.0') self._checkSample(bdist, filename) def test_ctor_w_egg_and_metadata_version(self): import os d, _ = os.path.split(__file__) filename = '%s/../../docs/examples/mypackage-0.1-py2.6.egg' % d bdist = self._makeOne(filename, metadata_version='1.1') self.assertEqual(bdist.metadata_version, '1.1') self._checkSample(bdist, filename) self._checkClassifiers(bdist) pkginfo-1.2.1/pkginfo/tests/sneaky/0000775000175000017500000000000012451564507020420 5ustar tseavertseaver00000000000000pkginfo-1.2.1/pkginfo/tests/sneaky/setup.py0000664000175000017500000000066412141476040022126 0ustar tseavertseaver00000000000000from setuptools import setup, find_packages setup( name='namespaced.sneaky', version='0.1', description='Test namespaced packages with non-root egg-info.', author='Tres Seaver', author_email='tseaver@palladion.com', long_description='Blah, blah.', packages=find_packages('src'), package_dir={'': 'src'}, namespace_packages=['namespaced',], install_requires=['setuptools'], zip_safe=False, ) pkginfo-1.2.1/pkginfo/tests/sneaky/src/0000775000175000017500000000000012451564507021207 5ustar tseavertseaver00000000000000pkginfo-1.2.1/pkginfo/tests/sneaky/src/namespaced/0000775000175000017500000000000012451564507023307 5ustar tseavertseaver00000000000000pkginfo-1.2.1/pkginfo/tests/sneaky/src/namespaced/__init__.py0000644000175000017500000000031012141474256025405 0ustar tseavertseaver00000000000000# this is a namespace package try: import pkg_resources pkg_resources.declare_namespace(__name__) except ImportError: import pkgutil __path__ = pkgutil.extend_path(__path__, __name__) pkginfo-1.2.1/pkginfo/tests/sneaky/src/namespaced/sneaky/0000775000175000017500000000000012451564507024601 5ustar tseavertseaver00000000000000pkginfo-1.2.1/pkginfo/tests/sneaky/src/namespaced/sneaky/__init__.py0000644000175000017500000000006312141474256026704 0ustar tseavertseaver00000000000000# Dummy package inside the 'namespaced' namespace. pkginfo-1.2.1/pkginfo/tests/sneaky/NOT-A-PACKAGE.txt0000644000175000017500000000022012141474277023020 0ustar tseavertseaver00000000000000THIS IS NOT A PYTHON PACKAGE!!!! It is meant to be added to sys.path for testing introspection of namespace packages installed via setuptools. pkginfo-1.2.1/pkginfo/utils.py0000644000175000017500000000322412245466164017476 0ustar tseavertseaver00000000000000import os from types import ModuleType from pkginfo.bdist import BDist from pkginfo.develop import Develop from pkginfo.installed import Installed from pkginfo.sdist import SDist from pkginfo.wheel import Wheel def get_metadata(path_or_module, metadata_version=None): """ Try to create a Distribution 'path_or_module'. o 'path_or_module' may be a module object. o If a string, 'path_or_module' may point to an sdist file, a bdist file, an installed package, or a working checkout (if it contains PKG-INFO). o Return None if 'path_or_module' can't be parsed. """ if isinstance(path_or_module, ModuleType): try: return Installed(path_or_module, metadata_version) except (ValueError, IOError): #pragma NO COVER pass try: __import__(path_or_module) except ImportError: pass else: try: return Installed(path_or_module, metadata_version) except (ValueError, IOError): #pragma NO COVER pass if os.path.isfile(path_or_module): try: return SDist(path_or_module, metadata_version) except (ValueError, IOError): pass try: return BDist(path_or_module, metadata_version) except (ValueError, IOError): #pragma NO COVER pass try: return Wheel(path_or_module, metadata_version) except (ValueError, IOError): #pragma NO COVER pass if os.path.isdir(path_or_module): try: return Develop(path_or_module, metadata_version) except (ValueError, IOError): #pragma NO COVER pass pkginfo-1.2.1/pkginfo/develop.py0000644000175000017500000000302212141477563017770 0ustar tseavertseaver00000000000000import os import sys import warnings from pkginfo.distribution import Distribution def _gather_py2(top, candidates): #pragma NO COVER Py3k def _filter(candidates, dirname, fnames): for fname in fnames: fqn = os.path.join(dirname, fname) if os.path.isdir(fqn): if fname == 'EGG-INFO' or fname.endswith('.egg-info'): candidates.append(fqn) os.path.walk(top, _filter, candidates) def _gather_py3(top, candidates): #pragma NO COVER Python2 for dirpath, dirnames, fnames in os.walk(top): for dirname in dirnames: fqn = os.path.join(dirpath, dirname) if dirname == 'EGG-INFO' or dirname.endswith('.egg-info'): candidates.append(fqn) if sys.version_info[0] < 3: #pragma NO COVER Python2 _gather = _gather_py2 else: #pragma NO COVER Py3k _gather = _gather_py3 class Develop(Distribution): def __init__(self, path, metadata_version=None): self.path = os.path.abspath( os.path.normpath( os.path.expanduser(path))) self.metadata_version = metadata_version self.extractMetadata() def read(self): candidates = [self.path] _gather(self.path, candidates) for candidate in candidates: path = os.path.join(candidate, 'PKG-INFO') if os.path.exists(path): with open(path) as f: return f.read() warnings.warn('No PKG-INFO found for path: %s' % self.path) pkginfo-1.2.1/pkginfo/commandline.py0000644000175000017500000001471412451555275020633 0ustar tseavertseaver00000000000000"""Print the metadata for one or more Python package distributions. Usage: %prog [options] path+ Each 'path' entry can be one of the following: o a source distribution: in this case, 'path' should point to an existing archive file (.tar.gz, .tar.bz2, or .zip) as generated by 'setup.py sdist'. o a binary distribution: in this case, 'path' should point to an existing archive file (.egg) o a "develop" checkout: in ths case, 'path' should point to a directory intialized via 'setup.py develop' (under setuptools). o an installed package: in this case, 'path' should be the importable name of the package. """ try: from configparser import ConfigParser except ImportError: # pragma: NO COVER from ConfigParser import ConfigParser from csv import writer import optparse import os import sys from pkginfo import get_metadata def _parse_options(args=None): parser = optparse.OptionParser(usage=__doc__) parser.add_option("-m", "--metadata-version", default=None, help="Override metadata version") parser.add_option("-f", "--field", dest="fields", action="append", help="Specify an output field (repeatable)", ) parser.add_option("-d", "--download-url-prefix", dest="download_url_prefix", help="Download URL prefix", ) parser.add_option("--simple", dest="output", action="store_const", const='simple', default='simple', help="Output as simple key-value pairs", ) parser.add_option("-s", "--skip", dest="skip", action="store_true", default=True, help="Skip missing values in simple output", ) parser.add_option("-S", "--no-skip", dest="skip", action="store_false", help="Don't skip missing values in simple output", ) parser.add_option("--single", dest="output", action="store_const", const='single', help="Output delimited values", ) parser.add_option("--item-delim", dest="item_delim", action="store", default=';', help="Delimiter for fields in single-line output", ) parser.add_option("--sequence-delim", dest="sequence_delim", action="store", default=',', help="Delimiter for multi-valued fields", ) parser.add_option("--csv", dest="output", action="store_const", const='csv', help="Output as CSV", ) parser.add_option("--ini", dest="output", action="store_const", const='ini', help="Output as INI", ) options, args = parser.parse_args(args) if len(args)==0: parser.error("Pass one or more files or directories as arguments.") else: return options, args class Base(object): _fields = None def __init__(self, options): if options.fields: self._fields = options.fields def finish(self): # pragma: NO COVER pass class Simple(Base): def __init__(self, options): super(Simple, self).__init__(options) self._skip = options.skip def __call__(self, meta): for field in self._fields or list(meta): value = getattr(meta, field) if (not self._skip) or (value is not None and value!=()): print("%s: %s" % (field, value)) class SingleLine(Base): _fields = None def __init__(self, options): super(SingleLine, self).__init__(options) self._item_delim = options.item_delim self._sequence_delim = options.sequence_delim def __call__(self, meta): if self._fields is None: self._fields = list(meta) values = [] for field in self._fields: value = getattr(meta, field) if isinstance(value, (tuple, list)): value = self._sequence_delim.join(value) else: value = str(value) values.append(value) print(self._item_delim.join(values)) class CSV(Base): _writer = None def __init__(self, options): super(CSV, self).__init__(options) self._sequence_delim = options.sequence_delim def __call__(self, meta): if self._fields is None: self._fields = list(meta) # first dist wins fields = self._fields if self._writer is None: self._writer = writer(sys.stdout) self._writer.writerow(fields) values = [] for field in fields: value = getattr(meta, field) if isinstance(value, (tuple, list)): value = self._sequence_delim.join(value) else: value = str(value) values.append(value) self._writer.writerow(values) class INI(Base): _fields = None def __init__(self, options): super(INI, self).__init__(options) self._parser = ConfigParser() def __call__(self, meta): name = meta.name version = meta.version section = '%s-%s' % (name, version) if self._parser.has_section(section): raise ValueError('Duplicate distribution: %s' % section) self._parser.add_section(section) for field in self._fields or list(meta): value = getattr(meta, field) if isinstance(value, (tuple, list)): value = '\n\t'.join(value) self._parser.set(section, field, value) def finish(self): self._parser.write(sys.stdout) # pragma: NO COVER _FORMATTERS = { 'simple': Simple, 'single': SingleLine, 'csv': CSV, 'ini': INI, } def main(args=None): """Entry point for pkginfo tool """ options, paths = _parse_options(args) format = getattr(options, 'output', 'simple') formatter = _FORMATTERS[format](options) for path in paths: meta = get_metadata(path, options.metadata_version) if meta is None: continue if options.download_url_prefix: if meta.download_url is None: filename = os.path.basename(path) meta.download_url = '%s/%s' % (options.download_url_prefix, filename) formatter(meta) formatter.finish() pkginfo-1.2.1/pkginfo/wheel.py0000664000175000017500000000265612245466420017447 0ustar tseavertseaver00000000000000from io import StringIO import os import zipfile from .distribution import Distribution from .distribution import must_decode from .distribution import parse class Wheel(Distribution): def __init__(self, filename, metadata_version=None): self.filename = filename self.metadata_version = metadata_version self.extractMetadata() def read(self): fqn = os.path.abspath(os.path.normpath(self.filename)) if not os.path.exists(fqn): raise ValueError('No such file: %s' % fqn) if fqn.endswith('.whl'): archive = zipfile.ZipFile(fqn) names = archive.namelist() def read_file(name): return archive.read(name) else: raise ValueError('Not a known archive format: %s' % fqn) try: tuples = [x.split('/') for x in names if 'METADATA' in x] schwarz = sorted([(len(x), x) for x in tuples]) for path in [x[1] for x in schwarz]: candidate = '/'.join(path) data = read_file(candidate) if b'Metadata-Version' in data: return data finally: archive.close() raise ValueError('No METADATA in archive: %s' % fqn) def parse(self, data): super(Wheel, self).parse(data) fp = StringIO(must_decode(data)) msg = parse(fp) self.description = msg.get_payload() pkginfo-1.2.1/pkginfo/sdist.py0000644000175000017500000000440312141471744017457 0ustar tseavertseaver00000000000000import os import tarfile import zipfile from pkginfo.distribution import Distribution class SDist(Distribution): def __init__(self, filename, metadata_version=None): self.filename = filename self.metadata_version = metadata_version self.extractMetadata() @classmethod def _get_archive(cls, fqn): if not os.path.exists(fqn): raise ValueError('No such file: %s' % fqn) if fqn.endswith('.zip'): archive = zipfile.ZipFile(fqn) names = archive.namelist() def read_file(name): return archive.read(name) elif fqn.endswith('gz') or fqn.endswith('bz2'): archive = tarfile.TarFile.open(fqn) names = archive.getnames() def read_file(name): return archive.extractfile(name).read() else: raise ValueError('Not a known archive format: %s' % fqn) return archive, names, read_file def read(self): fqn = os.path.abspath( os.path.normpath(self.filename)) archive, names, read_file = self._get_archive(fqn) try: tuples = [x.split('/') for x in names if 'PKG-INFO' in x] schwarz = sorted([(len(x), x) for x in tuples]) for path in [x[1] for x in schwarz]: candidate = '/'.join(path) data = read_file(candidate) if b'Metadata-Version' in data: return data finally: archive.close() raise ValueError('No PKG-INFO in archive: %s' % fqn) class UnpackedSDist(SDist): def __init__(self, filename, metadata_version=None): if os.path.isdir(filename): pass elif os.path.isfile(filename): filename = os.path.dirname(filename) else: raise ValueError('No such file: %s' % filename) super(UnpackedSDist, self).__init__( filename, metadata_version=metadata_version) def read(self): try: with open(os.path.join(self.filename, 'PKG-INFO')) as f: return f.read() except Exception as e: raise ValueError('Could not load %s as an unpacked sdist: %s' % (self.filename, e)) pkginfo-1.2.1/CHANGES.txt0000644000175000017500000001176312451564413016142 0ustar tseavertseaver00000000000000``pkginfo`` Changelog ===================== 1.2.1 (2014-01-02) ------------------ - Add overlooked Trove classifier for Python 3.4. 1.2 (2014-01-02) ---------------- - Add support for Python 3.4, PyPy3. - Add 100% coverage for ``pkginfo.commandline`` module. 1.2b1 (2013-12-05) ------------------ - Add support for the "wheel" distribution format, along with minimal metadata 2.0 support (not including new PEP 426 JSON properties). Code (re-)borrowed from Donald Stuft's ``twine`` package. 1.1 (2013-10-09) ---------------- - Fix tests to pass with current PyPy releases. 1.1b1 (2013-05-05) ------------------ - Support "develop" packages which keep their ``*.egg-info`` in a subdirectory. See https://bugs.launchpad.net/pkginfo/+bug/919147. - Add support for "unpacked SDists" (thanks to Mike Lundy for the patch). 1.0 (2013-05-05) ---------------- - No changes from 1.0b2. 1.0b2 (2012-12-28) ------------------ - Suppress resource warning leaks reported against clients. - Fix 'commandline' module under Py3k. 1.0b1 (2012-12-28) ------------------ - Add support for Python 3.2 and 3.3, including testing them under ``tox``. - Add support for PyPy, including testing it under ``tox``. - Test supported Python versions under ``tox``. - Drop support for Python 2.5. - Add a ``setup.py dev`` alias: runs ``setup.py develop`` and installs testing extras (``nose`` and ``coverage``). 0.9.1 (2012-10-22) ------------------ - Fix test failure under Python >= 2.7, which is enforcing 'metadata_version == 1.1' because we have classifiers. 0.9 (2012-04-25) ---------------- - Fix introspection of installed namespace packages. They may be installed as eggs or via dist-installed 'egg-info' files. https://bugs.launchpad.net/pkginfo/+bug/934311 - Avoid a regression in 0.8 under Python 2.6 / 2.7 when parsing unicode. https://bugs.launchpad.net/pkginfo/+bug/733827/comments/3 0.8 (2011-03-12) ---------------- - Work around Python 2.7's breakage of StringIO. Fixes https://bugs.launchpad.net/pkginfo/+bug/733827 - Fix bug in introspection of installed packages missing the ``__package__`` attribute. 0.7 (2010-11-04) ---------------- - Preserve newlines in the ``description`` field. Thanks to Sridhar Ratnakumar for the patch. - 100% test coverage. 0.6 (2010-06-01) ---------------- - Replace use of ``StringIO.StringIO`` with ``io.StringIO``, where available (Python >= 2.6). - Replace use of ``rfc822`` stdlib module with ``email.parser``, when available (Python >= 2.5). Ensured that distributions "unfold" wrapped continuation lines, stripping any leading / trailing whitespace, no matter which module was used for parsing. - Remove bogus testing dependency on ``zope.testing``. - Add tests that the "environment markers" spelled out in the approved PEP 345 are captured. - Add ``Project-URL`` for ``1.2`` PKG-INFO metdata (defined in the accepted version of PEP 345). 0.5 (2009-09-11) ---------------- - Marked package as non-zip-safe. - Fix Trove metadata misspelling. - Restore compatibility with Python 2.4. - Note that the introspection of installed packages / modules works only in Python 2.6 or later. - Add ``Index`` class as an abstraction over a collection of distributions. - Add ``download_url_prefix`` argument to ``pkginfo`` script. If passed, the script will use the prefix to synthesize a ``download_url`` for distributions which do not supply that value directly. 0.4.1 (2009-05-07) ------------------ - Fix bugs in handling of installed packages which lack ``__file__`` or ``PKG-INFO``. 0.4 (2009-05-07) ---------------- - Extend the console script to allow output as CSV or INI. Also, added arguments to specify the metadata version and other parsing / output policies. - Add support for the different metadata versions specified in PEPs 241, 314, and 345. Distributions now parse and expose only the attributes corresponding to their metadata version, which defaults to the version parsed from the ``PKG-INFO`` file. The programmer can override that version when creating the distribution object. 0.3 (2009-05-07) ---------------- - Add support for introspection of "development eggs" (checkouts with ``PKG-INFO``, perhaps created via ``setup.py develop``). - Add a console script, ``pkginfo``, which takes one or more paths on the command line and writes out the associated information. Thanks to ``runeh`` for the patch! - Add ``get_metadata`` helper function, which dispatches a given path or module across the available distribution types, and returns a distribution object. Thanks to ``runeh`` for the patch! - Make distribution objects support iteration over the metadata fields. Thanks to ``runeh`` for the patch! - Make ``Distribution`` and subclasses new-style classes. Thanks to ``runeh`` for the patch! 0.2 (2009-04-14) ---------------- - Add support for introspection of ``bdist_egg`` binary distributions. 0.1.1 (2009-04-10) ------------------ - Fix packaging errors. 0.1 (2009-04-10) ---------------- - Initial release. pkginfo-1.2.1/docs/0000775000175000017500000000000012451564507015257 5ustar tseavertseaver00000000000000pkginfo-1.2.1/docs/distributions.rst0000644000175000017500000001204312245467044020710 0ustar tseavertseaver00000000000000Distribution Types ================== The fundamental abstraction provided by this pacakge is the ``Distribution`` base class. Implementations exist for specific cases: source distributions, binary distributions, installed pakcages, and development checkouts. .. doctest:: >>> from pkginfo import Distribution >>> from pkginfo import SDist >>> assert issubclass(SDist, Distribution) >>> from pkginfo import UnpackedSDist >>> assert issubclass(UnpackedSDist, SDist) >>> from pkginfo import BDist >>> assert issubclass(BDist, Distribution) >>> from pkginfo import Wheel >>> assert issubclass(Wheel, Distribution) >>> from pkginfo import Installed >>> assert issubclass(Installed, Distribution) >>> from pkginfo import Develop >>> assert issubclass(Develop, Distribution) Introspecting Source Distributions ---------------------------------- ``SDist`` objects are created from a filesystem path to the corresponding archive, which should have been created via the ``sdist`` command from distutils: .. doctest:: >>> mypackage = SDist('docs/examples/mypackage-0.1.tar.gz') After creation, the ``SDist`` instance will have attributes corrsponding the the fields defined in the PEP corresponding to the metadata version, lower-cased and transliterated into valid Python identifiers by mapping hyphens to underscores. E.g.: .. doctest:: >>> print mypackage.metadata_version 1.0 >>> print mypackage.name mypackage >>> print mypackage.version 0.1 Fields which are optional under the PEP, and which have no value set in their ``PKG-INFO``, will map to the value ``None``: .. doctest:: >>> print mypackage.keywords None Fields which are marked "multiple use" under the PEP map onto sequences; their names are pluralized to indicate the sequence. "Multiple use" fields with no occurences in the ``PKG-INFO`` file will map onto an empty sequence: .. doctest:: >>> print list(mypackage.supported_platforms) [] See `Metadata Versions `_ for an example with a non-empty, "multiple-use" field. Introspecting Unpacked Source Distributions ------------------------------------------- You can also introspect a previously-unpacked package with ``UnpackedSDist`` either by passing it the path to the unpacked package, or by passing it the setup.py at the top level: .. doctest:: >>> mypackage = UnpackedSDist('docs/examples/mypackage-0.1') >>> print mypackage.name mypackage >>> myotherpackage = UnpackedSDist('docs/examples/mypackage-0.1/setup.py') >>> print myotherpackage.name mypackage ``UnpackedSDist`` objects are most useful in conjuction with distutils to produce sdists that want complex behavior for determining what metadata to use; these sdists normally break when installed with ``pip``, because metadata in an sdist is regenerated when pip installed. You can achieve this in your `setup.py` as follows: .. code:: >>> from setuptools import dist, setup >>> dist.Distribution(dict(setup_requires='pkginfo')) >>> from pkginfo import UnpackedSDist >>> try: ... d = UnpackedSDist(__file__) ... VERSION = d.version ... except ValueError: ... VERSION = (version_from_source_control() or ... os.getenv('VERSION', '1.0')) >>> setup(name='mypackage', version=VERSION) Introspecting Binary Distributions ---------------------------------- ``BDist`` objects are created from the filename, which should have been generated via ``setup.py bdist_egg``. .. doctest:: >>> mypackage = BDist('docs/examples/mypackage-0.1-py2.6.egg') After that, they have the same metadata as other ``Distribution`` objects, Introspecting Wheels -------------------- ``Wheel`` objects are created from the filename, which should have been generated via ``setup.py bdist_wheel``. .. doctest:: >>> mypackage = Wheel('docs/examples/mypackage-0.1-cp26-none-linux_x86_64.whl') After that, they have the same metadata as other ``Distribution`` objects, Introspecting Installed Packages -------------------------------- ``Installed`` objects are created from either a module object or its dotted name. Note that this feature only works in Python 2.6 or later: earlier Python versions did not record ``PKG-INFO`` for installed packages. .. doctest:: >>> import sys >>> if sys.version_info >= (2,6): ... dotted = Installed('pkginfo') ... import pkginfo ... direct = Installed(pkginfo) After that, they have the same metadata as other ``Distribution`` objects, assuming that the package on which they were based has a discoverable '.egg-info' file / directory. To be discoverable, the '.egg-info' must either be located inside the package (e.g., created via ``setup.py develop`` under setuptools), or adjacent to the package (e.g., created via ``setup.py instlall``). Introspecting Development Checkouts ----------------------------------- ``Develop`` objects are created from a path to a checkout containing a ``PKG-iNFO`` file, e.g., created by running ``setup.py develop`` under setuptools. .. doctest:: >>> develop = Develop('.') After that, they have the same metadata as other ``Distribution`` objects. pkginfo-1.2.1/docs/Makefile0000644000175000017500000000447711357450726016732 0ustar tseavertseaver00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d .build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html web pickle htmlhelp latex changes linkcheck help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " changes to make an overview over all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" clean: -rm -rf .build/* html: mkdir -p .build/html .build/doctrees $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) .build/html @echo @echo "Build finished. The HTML pages are in .build/html." pickle: mkdir -p .build/pickle .build/doctrees $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) .build/pickle @echo @echo "Build finished; now you can process the pickle files." web: pickle json: mkdir -p .build/json .build/doctrees $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) .build/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: mkdir -p .build/htmlhelp .build/doctrees $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) .build/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in .build/htmlhelp." latex: mkdir -p .build/latex .build/doctrees $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) .build/latex @echo @echo "Build finished; the LaTeX files are in .build/latex." @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ "run these through (pdf)latex." changes: mkdir -p .build/changes .build/doctrees $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) .build/changes @echo @echo "The overview file is in .build/changes." linkcheck: mkdir -p .build/linkcheck .build/doctrees $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) .build/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in .build/linkcheck/output.txt." pkginfo-1.2.1/docs/metadata.rst0000644000175000017500000000232111457313144017557 0ustar tseavertseaver00000000000000Metadata Versions ================= The allowed ``PKG-INFO`` fields and their semantics are defined in a series of PEPs, each of which updates the metadata version field. - Metadata version 1.0 is specified in `PEP 241`_. - Metadata version 1.1 is specified in `PEP 314`_. - Metadata version 1.2 is specified in `PEP 345`_ (still in draft). A given ``Distribution`` object parses / exposes the attributes which correspond to the metadata version specified in its ``PKG-INFO``. You can override the metadata version stored in a given distribution by passing the specific version (as a string) to its constructor. E.g., updating the metadata version here in order to expose the classifiers, which were not defined under version '1.0': .. doctest:: >>> from pkginfo import SDist >>> mypackage = SDist('docs/examples/mypackage-0.1.tar.gz', ... metadata_version='1.1') >>> print [str(x) for x in mypackage.classifiers] ['Development Status :: 4 - Beta', 'Environment :: Console (Text Based)'] .. _`PEP 241`: http://svn.python.org/projects/peps/trunk/pep-0241.txt .. _`PEP 314`: http://svn.python.org/projects/peps/trunk/pep-0314.txt .. _`PEP 345`: http://svn.python.org/projects/peps/trunk/pep-0345.txt pkginfo-1.2.1/docs/conf.py0000644000175000017500000001372312451562364016561 0ustar tseavertseaver00000000000000# -*- coding: utf-8 -*- # # pkginfo documentation build configuration file, created by # sphinx-quickstart on Wed Apr 8 19:26:04 2009. # # This file is execfile()d with the current directory set to its containing dir. # # The contents of this file are pickled, so don't put values in the namespace # that aren't pickleable (module imports are okay, they're removed automatically). # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os # If your extensions are in another directory, add it here. If the directory # is relative to the documentation root, use os.path.abspath to make it # absolute, like shown here. #sys.path.append(os.path.abspath('.')) # General configuration # --------------------- # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.doctest', ] doctest_path = [os.path.abspath('..')] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8' # The master toctree document. master_doc = 'index' # General information about the project. project = u'pkginfo' copyright = u'2009-2013, Tres Seaver' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '1.2' # The full version, including alpha/beta/rc tags. release = '1.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of documents that shouldn't be included in the build. #unused_docs = [] # List of directories, relative to source directory, that shouldn't be searched # for source files. exclude_trees = ['.build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # Options for HTML output # ----------------------- # The style sheet to use for HTML and HTML Help pages. A file of that name # must exist either in Sphinx' static/ path, or in one of the custom paths # given in html_static_path. html_style = 'default.css' # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_use_modindex = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, the reST sources are included in the HTML build as _sources/. #html_copy_source = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = '' # Output file base name for HTML help builder. htmlhelp_basename = 'pkginfodoc' # Options for LaTeX output # ------------------------ # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, document class [howto/manual]). latex_documents = [ ('index', 'pkginfo.tex', ur'pkginfo Documentation', ur'Tres Seaver', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_use_modindex = True pkginfo-1.2.1/docs/indexes.rst0000644000175000017500000000107411357450726017451 0ustar tseavertseaver00000000000000Distribution Indexes ===================== An ``Index`` is conceptually a set of ``Distribution`` objects, with some additional behavior for managing the set as a whole. .. doctest:: >>> from pkginfo import Distribution >>> from pkginfo import Index >>> index = Index() >>> list(index) [] >>> d1 = Distribution() >>> d1.name = 'foo' >>> d1.version = '1.0' >>> index.add(d1) >>> list(index) ['foo-1.0'] >>> d2 = Distribution() >>> d2.name = 'foo' >>> d2.version = '1.1' >>> index.add(d2) >>> sorted(list(index)) ['foo-1.0', 'foo-1.1'] pkginfo-1.2.1/docs/index.rst0000644000175000017500000000104712245467162017120 0ustar tseavertseaver00000000000000:mod:`pkginfo` documentation ============================ This package provides an API for querying the distutils metadata written in the ``PKG-INFO`` file inside a source distriubtion (an ``sdist``) or a binary distribution (e.g., created by running ``bdist_egg`` or ``bdist_wheel``). It can also query the ``EGG-INFO`` directory of an installed distribution, and the ``*.egg-info`` stored in a "development checkout" (e.g, created by running ``setup.py develop``). Contents: .. toctree:: :maxdepth: 2 distributions metadata indexes pkginfo-1.2.1/docs/examples/0000775000175000017500000000000012451564507017075 5ustar tseavertseaver00000000000000pkginfo-1.2.1/docs/examples/mypackage-0.1/0000775000175000017500000000000012451564507021332 5ustar tseavertseaver00000000000000pkginfo-1.2.1/docs/examples/mypackage-0.1/setup.cfg0000664000175000017500000000007312141471267023147 0ustar tseavertseaver00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 pkginfo-1.2.1/docs/examples/mypackage-0.1/PKG-INFO0000664000175000017500000000047612141471267022432 0ustar tseavertseaver00000000000000Metadata-Version: 1.0 Name: mypackage Version: 0.1 Summary: UNKNOWN Home-page: http://pypi.python.org/pypi/pkginfo Author: Tres Seaver Author-email: tseaver@palladion.com License: UNKNOWN Description: UNKNOWN Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Environment :: Console (Text Based) pkginfo-1.2.1/docs/examples/mypackage-0.1/setup.py0000664000175000017500000000046512141471267023045 0ustar tseavertseaver00000000000000from setuptools import setup setup( name='mypackage', version='0.1', author='Tres Seaver', author_email='tseaver@palladion.com', url='http://pypi.python.org/pypi/pkginfo', classifiers=[ 'Development Status :: 4 - Beta', 'Environment :: Console (Text Based)', ], ) pkginfo-1.2.1/docs/examples/mypackage-0.1/README.txt0000664000175000017500000000011212141471267023016 0ustar tseavertseaver00000000000000mypackage README ================ Dummy package for testing ``pkginfo``. pkginfo-1.2.1/docs/examples/mypackage-0.1-cp26-none-linux_x86_64.whl0000664000175000017500000000343012245463355025726 0ustar tseavertseaver00000000000000PK{C^- 'mypackage-0.1.dist-info/DESCRIPTION.rst PK{C )$#mypackage-0.1.dist-info/pydist.jsonMKO0S+S*N9>$*"g%{SwCof3g8T[0yμ(MoXnoj]_LAE  Oy*&Ig $gрyD!ٟ76EVݳYj+;"1F[%6͘.PK{C2%mypackage-0.1.dist-info/top_level.txtPK {C`ggmypackage-0.1.dist-info/WHEEL HM K-*ϳR03rOK-J,/RHJ,./Q0323 /, (-JLRHK)N ILRH.02K+073PK{Cç!4 mypackage-0.1.dist-info/METADATAUN0 @ tCr I@Aꀳպ]$OTG??/$أ`A)[nF5ɀ_"vgI-7z{Lylԁ=UxN"u\qi\:GVS1Qp*h+%;v2]oe/d0g;X*h&She` B?16qX9dvWGaZ߆RPK {CL7mypackage-0.1.dist-info/RECORDu;s@ AZ@XA`qPvW>Ia:[̹I]p<0aouּ<=8M\Ă$4ܺFoAIJj&RD6ڤ!40gՄ}2^f8CTؓzRC> NQ[SiQN93cEGG-INFO/PKG-INFOUMK0@sC]jyhݰI&$by B= V``7AOHo[NcZ 7OgSg,M]%Z9sМuea`0 eh gJ?"a_ºcmG!ӵ{%e9Ü`44)2e0]y?f8jq2;} 0SPKIN:2EGG-INFO/zip-safePKIN:2EGG-INFO/dependency_links.txtPKIN:sXn`>EGG-INFO/SOURCES.txtPKIN:2EGG-INFO/top_level.txtPKIN:$1@.>EGG-INFO/PKG-INFOPKIN:2EGG-INFO/zip-safePKOCpkginfo-1.2.1/docs/examples/mypackage-0.1.tar.gz0000644000175000017500000000140511357450726022460 0ustar tseavertseaver00000000000000]Imypackage-0.1.tarN0s]A"i E@Qؽ@&nHbv*iR z<+|C9E5JnVW{RVv)Ͳ,Ϸ]ϳmʹzkZPbjc4Q?vGC܈MsGoY*/,ǗiM=/|nS \E'zŔL&Д><4{ka I2%e0u'Ffb,))j2-*-u?O_?1.8Kkgi_{"UU`;sWuMm:d71x:C 7 p𿁰~W?Y{?<:H 'fN-CeQx><$:~.T$) ’mފn),g s8W8GifPe(ayG,eKIĔֲ!ij'#4Dž#Da@pO.Ě렘''[gF=q >}#;_^[so: MavAHaSO[J$UtvjlQŽ̞ƄjF5aAϒIԒ=ZaËR4wk޸_mugRRR TZ(pkginfo-1.2.1/docs/examples/nodistinfo-0.1-any.whl0000644000175000017500000000167312245461032023041 0ustar tseavertseaver00000000000000PK ld= EGG-INFO/UT  L6Lux PK IN:2EGG-INFO/zip-safeUT IIux  PKIN:sXn`EGG-INFO/SOURCES.txtUT IIux  rutu+(*N-)-KNK *r+ SRu3u=9M"Z\]K]I~A|NjYjHPK IN:2EGG-INFO/top_level.txtUT IIux  PK IN:2EGG-INFO/dependency_links.txtUT IIux  PK ld= AEGG-INFO/UT Lux PK IN:2CEGG-INFO/zip-safeUTIux PKIN:sXn`EGG-INFO/SOURCES.txtUTIux PK IN:2=EGG-INFO/top_level.txtUTIux PK IN:2EGG-INFO/dependency_links.txtUTIux PKpkginfo-1.2.1/docs/examples/mypackage-0.1.zip0000644000175000017500000000375411357450726022066 0ustar tseavertseaver00000000000000PKB:8Jmypackage-0.1/README.txt˭,HLNLOUrutuE\\. 0eiE %%y yi z\PK:DV2;mypackage-0.1/setup.cfgNMOKˏ*ILO*IQUsRKRl0,/(,83?,PK:$1@.>mypackage-0.1/PKG-INFOUMK0@sC]jyhݰI&$by B= V``7AOHo[NcZ 7OgSg,M]%Z9sМuea`0 eh gJ?"a_ºcmG!ӵ{%e9Ü`44)2e0]y?f8jq2;} 0SPK:95mypackage-0.1/setup.pyUAk0 .`at/hoe *m[ Ϳwz{BSbd2X9ɟT;E=g҇ꮔ`s,\s '‚KɣuFK[DZt#F.78}ܢV4׽ن>:N)mypackage-0.1/mypackage.egg-info/PKG-INFOUMK0@sC]jyhݰI&$by B= V``7AOHo[NcZ 7OgSg,M]%Z9sМuea`0 eh gJ?"a_ºcmG!ӵ{%e9Ü`44)2e0]y?f8jq2;} 0SPKB:8Jmypackage-0.1/README.txtPK:DV2;nmypackage-0.1/setup.cfgPK:$1@.>mypackage-0.1/PKG-INFOPK:95mypackage-0.1/setup.pyPK:25mypackage-0.1/mypackage.egg-info/dependency_links.txtPK:JyD[,=mypackage-0.1/mypackage.egg-info/SOURCES.txtPK:2.mypackage-0.1/mypackage.egg-info/top_level.txtPK:$1@.>)1mypackage-0.1/mypackage.egg-info/PKG-INFOPKSpkginfo-1.2.1/docs/examples/nopkginfo-0.1.egg0000644000175000017500000000167311464567504022057 0ustar tseavertseaver00000000000000PK ld= EGG-INFO/UT  L6Lux PK IN:2EGG-INFO/zip-safeUT IIux  PKIN:sXn`EGG-INFO/SOURCES.txtUT IIux  rutu+(*N-)-KNK *r+ SRu3u=9M"Z\]K]I~A|NjYjHPK IN:2EGG-INFO/top_level.txtUT IIux  PK IN:2EGG-INFO/dependency_links.txtUT IIux  PK ld= AEGG-INFO/UT Lux PK IN:2CEGG-INFO/zip-safeUTIux PKIN:sXn`EGG-INFO/SOURCES.txtUTIux PK IN:2=EGG-INFO/top_level.txtUTIux PK IN:2EGG-INFO/dependency_links.txtUTIux PKpkginfo-1.2.1/docs/examples/mypackage-0.1.tar.bz20000644000175000017500000000157111357450726022541 0ustar tseavertseaver00000000000000BZh91AY&SY¯ǔ@ߊ` P @R2 4ji2a40@ #L04TQ@ RM4i@H@$eOiħOQ==G!??viwt]2l0^ .i]@Y-r)wJWV\\A0$`x弦 :YAy6k-;2 ؅ְ+:Gnŝm礊AV|&. H h1^1*0A1Aǥdw|}e)ϒL cq(q-2SCJvgooH +8+ĥHHD?2W/lİEtt3*dlX d`+ f H%~V Y"QTH:O#?\(((K ,`#HZZy=@P{V~ϰ[CJa1dp"@iً5Fi}vpJ;:|@fytT%ݱ?& 7a:jb.979[BI&;IppZ`;\e2b/>#o4{( -B> .~V`!,8yX `91+XY)rfiq'a2';uy