pkginfo-1.4.2/0000775000175000017500000000000013252256452014327 5ustar tseavertseaver00000000000000pkginfo-1.4.2/CHANGES.txt0000664000175000017500000001376413252255670016154 0ustar tseavertseaver00000000000000``pkginfo`` Changelog ===================== 1.4.2 (2018-03-14) ------------------ - Use relative imports in pkginfo modules. Supports vendoring of the package into setuptools. - Add support for ``Provides-Extra`` and ``Description-Content-Type`` fields. Per https://packaging.python.org/specifications/. See: PEP 566. - Remove support for old setuptools leaving ``PKG-INFO`` in the root of the project directory. 1.4.1 (2016-11-07) ------------------ - Packaging only change (invalid sdist built for 1.4.0). 1.4.0 (2016-11-04) ------------------ - Relicense under MIT license: the PSF license is not suitable for third-party libraries. 1.3.2 (2016-05-24) ------------------ - Packaging-only change (automate fix for wheel built for 1.3.1). 1.3.1 (2016-05-24) ------------------ - Packaging-only change (invalid wheel built for 1.3.0). 1.3.0 (2016-05-23) ------------------ - Update homepage URL to point to Launchpad, rather than PyPI. - Add support for building wheels. - Add support for Python 3.5. - Drop support for Python 2.6 and 3.2. 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.4.2/.bzrignore0000664000175000017500000000013413250316705016323 0ustar tseavertseaver00000000000000*.egg-info ./build ./dist .coverage __pycache__ .tox coverage.xml nosetests.xml docs/_build pkginfo-1.4.2/TODO.txt0000664000175000017500000000054613250316705015636 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.4.2/setup.cfg0000664000175000017500000000033413252256452016150 0ustar tseavertseaver00000000000000[bdist_wheel] universal = 1 [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 pkginfo-1.4.2/pkginfo.egg-info/0000775000175000017500000000000013252256452017456 5ustar tseavertseaver00000000000000pkginfo-1.4.2/pkginfo.egg-info/dependency_links.txt0000664000175000017500000000000113252256452023524 0ustar tseavertseaver00000000000000 pkginfo-1.4.2/pkginfo.egg-info/entry_points.txt0000664000175000017500000000006613252256452022756 0ustar tseavertseaver00000000000000[console_scripts] pkginfo = pkginfo.commandline:main pkginfo-1.4.2/pkginfo.egg-info/PKG-INFO0000664000175000017500000002275313252256452020564 0ustar tseavertseaver00000000000000Metadata-Version: 1.1 Name: pkginfo Version: 1.4.2 Summary: Query metadatdata from sdists / bdists / installed packages. Home-page: https://code.launchpad.net/~tseaver/pkginfo/trunk Author: Tres Seaver, Agendaless Consulting Author-email: tseaver@agendaless.com License: MIT Description-Content-Type: UNKNOWN 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.4.2 (2018-03-14) ------------------ - Use relative imports in pkginfo modules. Supports vendoring of the package into setuptools. - Add support for ``Provides-Extra`` and ``Description-Content-Type`` fields. Per https://packaging.python.org/specifications/. See: PEP 566. - Remove support for old setuptools leaving ``PKG-INFO`` in the root of the project directory. 1.4.1 (2016-11-07) ------------------ - Packaging only change (invalid sdist built for 1.4.0). 1.4.0 (2016-11-04) ------------------ - Relicense under MIT license: the PSF license is not suitable for third-party libraries. 1.3.2 (2016-05-24) ------------------ - Packaging-only change (automate fix for wheel built for 1.3.1). 1.3.1 (2016-05-24) ------------------ - Packaging-only change (invalid wheel built for 1.3.0). 1.3.0 (2016-05-23) ------------------ - Update homepage URL to point to Launchpad, rather than PyPI. - Add support for building wheels. - Add support for Python 3.5. - Drop support for Python 2.6 and 3.2. 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 :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 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.4.2/pkginfo.egg-info/top_level.txt0000664000175000017500000000001013252256452022177 0ustar tseavertseaver00000000000000pkginfo pkginfo-1.4.2/pkginfo.egg-info/not-zip-safe0000664000175000017500000000000113250317105021673 0ustar tseavertseaver00000000000000 pkginfo-1.4.2/pkginfo.egg-info/requires.txt0000664000175000017500000000003113252256452022050 0ustar tseavertseaver00000000000000 [testing] nose coverage pkginfo-1.4.2/pkginfo.egg-info/SOURCES.txt0000664000175000017500000000342013252256452021341 0ustar tseavertseaver00000000000000.bzrignore CHANGES.txt LICENSE.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/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.4.2/docs/0000775000175000017500000000000013252256452015257 5ustar tseavertseaver00000000000000pkginfo-1.4.2/docs/distributions.rst0000664000175000017500000001204313250316705020707 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.4.2/docs/metadata.rst0000664000175000017500000000232113250316705017563 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.4.2/docs/examples/0000775000175000017500000000000013252256452017075 5ustar tseavertseaver00000000000000pkginfo-1.4.2/docs/examples/mypackage-0.1-py2.6.egg0000664000175000017500000000165013250316705022670 0ustar tseavertseaver00000000000000PKIN:2EGG-INFO/dependency_links.txtPKIN:sXn`EGG-INFO/SOURCES.txt rutu+(*N-)-KNK *r+ SRu3u=9M"Z\]K]I~A|NjYjHPKIN:2EGG-INFO/top_level.txtPKIN:$1@.>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;} 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.4.2/docs/examples/mypackage-0.1.tar.bz20000664000175000017500000000157113250316705022536 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<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.4.2/docs/examples/nopkginfo-0.1.egg0000664000175000017500000000167313250316705022052 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.4.2/docs/examples/mypackage-0.1-cp26-none-linux_x86_64.whl0000664000175000017500000000343013250316705025722 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[SiQN93cmypackage-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.4.2/docs/examples/nopkginfo-0.1.zip0000664000175000017500000000167313250316705022112 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.4.2/docs/examples/nodistinfo-0.1-any.whl0000664000175000017500000000167313250316705023051 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.4.2/docs/conf.py0000664000175000017500000001372313250316705016560 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.4.2/docs/Makefile0000664000175000017500000000447713250316705016727 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.4.2/docs/indexes.rst0000664000175000017500000000107413250316705017446 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.4.2/docs/index.rst0000664000175000017500000000104713250316705017116 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.4.2/pkginfo/0000775000175000017500000000000013252256452015764 5ustar tseavertseaver00000000000000pkginfo-1.4.2/pkginfo/__init__.py0000664000175000017500000000041213250320376020065 0ustar tseavertseaver00000000000000from .bdist import BDist from .develop import Develop from .distribution import Distribution from .index import Index from .installed import Installed from .sdist import SDist from .sdist import UnpackedSDist from .utils import get_metadata from .wheel import Wheel pkginfo-1.4.2/pkginfo/develop.py0000664000175000017500000000301313250320376017764 0ustar tseavertseaver00000000000000import os import sys import warnings from .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.4.2/pkginfo/sdist.py0000664000175000017500000000437413250320376017467 0ustar tseavertseaver00000000000000import os import tarfile import zipfile from .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.4.2/pkginfo/bdist.py0000664000175000017500000000225613250320376017443 0ustar tseavertseaver00000000000000import os import zipfile from .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.4.2/pkginfo/installed.py0000664000175000017500000000366513250320376020322 0ustar tseavertseaver00000000000000import glob import os import sys import warnings from .distribution import Distribution from ._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.4.2/pkginfo/index.py0000664000175000017500000000100613250320376017435 0ustar tseavertseaver00000000000000from .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.4.2/pkginfo/distribution.py0000664000175000017500000001023313250320420021035 0ustar tseavertseaver00000000000000from email.parser import Parser from ._compat import StringIO from ._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_2_1 = HEADER_ATTRS_1_2 + ( # PEP 566 ('Provides-Extra', 'provides_extras', True), ('Description-Content-Type', 'description_content_type', False) ) 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, '2.1': HEADER_ATTRS_2_1, } 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 = () # version 2.1 provides_extras = () description_content_type = None 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) body = msg.get_payload() if body: setattr(self, 'description', body) def __iter__(self): for header_name, attr_name, multiple in self._getHeaderAttrs(): yield attr_name iterkeys = __iter__ pkginfo-1.4.2/pkginfo/wheel.py0000664000175000017500000000223713250317256017444 0ustar tseavertseaver00000000000000import os import zipfile from .distribution import Distribution 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) pkginfo-1.4.2/pkginfo/tests/0000775000175000017500000000000013252256452017126 5ustar tseavertseaver00000000000000pkginfo-1.4.2/pkginfo/tests/__init__.py0000664000175000017500000000247513250316705021243 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 :: MIT License', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', '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.4.2/pkginfo/tests/test_commandline.py0000664000175000017500000002350613250316705023027 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.4.2/pkginfo/tests/test_sdist.py0000664000175000017500000001155313250316705021666 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.4.2/pkginfo/tests/funny/0000775000175000017500000000000013252256452020265 5ustar tseavertseaver00000000000000pkginfo-1.4.2/pkginfo/tests/funny/__init__.py0000664000175000017500000000010413250316705022365 0ustar tseavertseaver00000000000000# sample installed package w/ .egg-info file. __package__ = 'funny' pkginfo-1.4.2/pkginfo/tests/funny/funny.egg-info0000664000175000017500000000005713250316705023037 0ustar tseavertseaver00000000000000Metadata-Version: 1.0 Name: funny Version: 0.1 pkginfo-1.4.2/pkginfo/tests/manky/0000775000175000017500000000000013252256452020245 5ustar tseavertseaver00000000000000pkginfo-1.4.2/pkginfo/tests/manky/namespaced.manky-0.1.egg-info/0000775000175000017500000000000013252256452025451 5ustar tseavertseaver00000000000000pkginfo-1.4.2/pkginfo/tests/manky/namespaced.manky-0.1.egg-info/PKG-INFO0000664000175000017500000000005513250316705026542 0ustar tseavertseaver00000000000000Metadata-Version: 1.0 Name: namespaced.wonky pkginfo-1.4.2/pkginfo/tests/manky/NOT-A-PACKAGE.txt0000664000175000017500000000022013250316705022643 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.4.2/pkginfo/tests/manky/namespaced/0000775000175000017500000000000013252256452022345 5ustar tseavertseaver00000000000000pkginfo-1.4.2/pkginfo/tests/manky/namespaced/__init__.py0000664000175000017500000000031013250316705024444 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.4.2/pkginfo/tests/manky/namespaced/manky/0000775000175000017500000000000013252256452023464 5ustar tseavertseaver00000000000000pkginfo-1.4.2/pkginfo/tests/manky/namespaced/manky/__init__.py0000664000175000017500000000006313250316705025570 0ustar tseavertseaver00000000000000# Dummy package inside the 'namespaced' namespace. pkginfo-1.4.2/pkginfo/tests/test_wheel.py0000664000175000017500000000457013250316705021645 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.4.2/pkginfo/tests/test_develop.py0000664000175000017500000000147713250317133022176 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_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.4.2/pkginfo/tests/wonky/0000775000175000017500000000000013252256452020275 5ustar tseavertseaver00000000000000pkginfo-1.4.2/pkginfo/tests/wonky/EGG-INFO/0000775000175000017500000000000013252256452021430 5ustar tseavertseaver00000000000000pkginfo-1.4.2/pkginfo/tests/wonky/EGG-INFO/PKG-INFO0000664000175000017500000000005513250316705022521 0ustar tseavertseaver00000000000000Metadata-Version: 1.0 Name: namespaced.wonky pkginfo-1.4.2/pkginfo/tests/wonky/NOT-A-PACKAGE.txt0000664000175000017500000000022013250316705022673 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.4.2/pkginfo/tests/wonky/namespaced/0000775000175000017500000000000013252256452022375 5ustar tseavertseaver00000000000000pkginfo-1.4.2/pkginfo/tests/wonky/namespaced/__init__.py0000664000175000017500000000031013250316705024474 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.4.2/pkginfo/tests/wonky/namespaced/wonky/0000775000175000017500000000000013252256452023544 5ustar tseavertseaver00000000000000pkginfo-1.4.2/pkginfo/tests/wonky/namespaced/wonky/__init__.py0000664000175000017500000000006313250316705025650 0ustar tseavertseaver00000000000000# Dummy package inside the 'namespaced' namespace. pkginfo-1.4.2/pkginfo/tests/test_distribution.py0000664000175000017500000004047713250317256023270 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_2_1(self): from pkginfo.distribution import HEADER_ATTRS_2_1 dist = self._makeOne(None) dist.parse('Metadata-Version: 2.1') self.assertEqual(dist.metadata_version, '2.1') self.assertEqual(list(dist), [x[1] for x in HEADER_ATTRS_2_1]) 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_Description_in_payload(self): dist = self._makeOne() dist.parse('Foo: Bar\n' '\n' '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.4.2/pkginfo/tests/test_bdist.py0000664000175000017500000000434713250316705021650 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.4.2/pkginfo/tests/test_index.py0000664000175000017500000000511413250316705021643 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.4.2/pkginfo/tests/test_installed.py0000664000175000017500000001303513250316705022514 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.4.2/pkginfo/tests/test_utils.py0000664000175000017500000001526313250316705021702 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.4.2/pkginfo/tests/silly/0000775000175000017500000000000013252256452020262 5ustar tseavertseaver00000000000000pkginfo-1.4.2/pkginfo/tests/silly/PKG-INFO0000664000175000017500000000005713250316705021355 0ustar tseavertseaver00000000000000Metadata-Version: 1.0 Name: silly Version: 0.1 pkginfo-1.4.2/pkginfo/utils.py0000664000175000017500000000315113250320376017471 0ustar tseavertseaver00000000000000import os from types import ModuleType from .bdist import BDist from .develop import Develop from .installed import Installed from .sdist import SDist from .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.4.2/pkginfo/_compat.py0000664000175000017500000000156513250316705017763 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.4.2/pkginfo/commandline.py0000664000175000017500000001471213250320376020624 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 .utils 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.4.2/PKG-INFO0000664000175000017500000002275313252256452015435 0ustar tseavertseaver00000000000000Metadata-Version: 1.1 Name: pkginfo Version: 1.4.2 Summary: Query metadatdata from sdists / bdists / installed packages. Home-page: https://code.launchpad.net/~tseaver/pkginfo/trunk Author: Tres Seaver, Agendaless Consulting Author-email: tseaver@agendaless.com License: MIT Description-Content-Type: UNKNOWN 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.4.2 (2018-03-14) ------------------ - Use relative imports in pkginfo modules. Supports vendoring of the package into setuptools. - Add support for ``Provides-Extra`` and ``Description-Content-Type`` fields. Per https://packaging.python.org/specifications/. See: PEP 566. - Remove support for old setuptools leaving ``PKG-INFO`` in the root of the project directory. 1.4.1 (2016-11-07) ------------------ - Packaging only change (invalid sdist built for 1.4.0). 1.4.0 (2016-11-04) ------------------ - Relicense under MIT license: the PSF license is not suitable for third-party libraries. 1.3.2 (2016-05-24) ------------------ - Packaging-only change (automate fix for wheel built for 1.3.1). 1.3.1 (2016-05-24) ------------------ - Packaging-only change (invalid wheel built for 1.3.0). 1.3.0 (2016-05-23) ------------------ - Update homepage URL to point to Launchpad, rather than PyPI. - Add support for building wheels. - Add support for Python 3.5. - Drop support for Python 2.6 and 3.2. 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 :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 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.4.2/tox.ini0000664000175000017500000000170613250316705015642 0ustar tseavertseaver00000000000000[tox] envlist = py27,pypy,py33,py34,py35,pypy3,cover2,cover3,docs [testenv] commands = python setup.py develop python setup.py test -q [testenv:cover2] basepython = python2.7 commands = python setup.py develop python setup.py nosetests --with-xunit --with-xcoverage deps = nose coverage nosexcover [testenv:cover3] basepython = python3.3 commands = python setup.py develop python setup.py nosetests --with-xunit --with-xcoverage deps = nose coverage nosexcover [testenv:docs] basepython = python2.7 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.4.2/README.txt0000664000175000017500000000102013250316705016012 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.4.2/LICENSE.txt0000664000175000017500000000207413250316705016151 0ustar tseavertseaver00000000000000MIT License Copyright (c) 2009 Agendaless Consulting, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pkginfo-1.4.2/setup.py0000664000175000017500000000321013252254766016043 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.4.2', description='Query metadatdata from sdists / bdists / installed packages.', platforms=['Unix', 'Windows'], long_description='\n\n'.join([README, CHANGES]), keywords='distribution sdist installed metadata', url='https://code.launchpad.net/~tseaver/pkginfo/trunk', author='Tres Seaver, Agendaless Consulting', author_email='tseaver@agendaless.com', license='MIT', classifiers=[ 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', '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 )