Import Upstream version 1.8.2
This commit is contained in:
commit
cf42014c48
|
@ -0,0 +1,9 @@
|
|||
*.egg-info
|
||||
./build
|
||||
./dist
|
||||
.coverage
|
||||
__pycache__
|
||||
.tox
|
||||
coverage.xml
|
||||
nosetests.xml
|
||||
docs/_build
|
|
@ -0,0 +1,3 @@
|
|||
[report]
|
||||
show_missing=1
|
||||
|
|
@ -0,0 +1,316 @@
|
|||
``pkginfo`` Changelog
|
||||
=====================
|
||||
|
||||
1.8.2 (2021-12-01)
|
||||
------------------
|
||||
|
||||
- Add fix for installed distributions with '__package__' set to an empty
|
||||
string. LP #1952946.
|
||||
|
||||
1.8.1 (2021-11-19)
|
||||
------------------
|
||||
|
||||
- Add 'MANIFEST.in' to ensure example files used by tests are included
|
||||
in source distributions. LP #1951553.
|
||||
|
||||
1.8.0 (2021-11-18)
|
||||
------------------
|
||||
|
||||
- Support new standard metadata location for installed dists. LP #1865286.
|
||||
|
||||
- Don't overwrite header-based 'description' with empty payload. LP #1885458.
|
||||
|
||||
- Add support for Metadata-Version 2.2. LP #1928729.
|
||||
|
||||
- Add support for uncompressed tarballs for sdists. LP #1951457.
|
||||
|
||||
- Add support for Python 3.10.
|
||||
|
||||
1.7.1 (2021-07-09)
|
||||
------------------
|
||||
|
||||
- Use Python3 to build docs, and fix doctest examples to use Python3-
|
||||
compatible syntax. LP #1933322.
|
||||
|
||||
1.7.0 (2021-01-16)
|
||||
------------------
|
||||
|
||||
- Add support for Python 3.9.
|
||||
|
||||
- Drop support for Python 3.5.
|
||||
|
||||
1.6.1 (2020-10-26)
|
||||
------------------
|
||||
|
||||
- Adjust test classifiers to match supported Python versions. LP #1901127.
|
||||
|
||||
1.6.0 (2020-10-20)
|
||||
------------------
|
||||
|
||||
- Add support for Python 3.8.
|
||||
LP #1869854.
|
||||
|
||||
- Drop support for Python 3.4.
|
||||
|
||||
- Update tests to match setuptools' change, no longer reporting metadata
|
||||
version for installed packages w/o explicit metadata. LP #1870197.
|
||||
|
||||
1.5.0.1 (2019-01-08)
|
||||
--------------------
|
||||
|
||||
- Fix broken 'sdist'. LP #1639585.
|
||||
|
||||
1.5.0 (2019-01-07)
|
||||
------------------
|
||||
|
||||
- Fix 'console_scripts' entry point syntax. LP #1810734.
|
||||
|
||||
- Add support for JSON output from the CLI. LP #1700580.
|
||||
|
||||
- Add support for installed wheels. E.g., 'dist-info/' dirs. LP #1700200.
|
||||
|
||||
- Harden metadata extraction against unexpected encodings. LP #1780454.
|
||||
|
||||
- Update tests to match pip/setuptools' use of new metadata version.
|
||||
LP #1772274.
|
||||
|
||||
- Add support for Python 3.6 and 3.7.
|
||||
|
||||
- Drop support for Python 3.3.
|
||||
|
||||
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.
|
|
@ -0,0 +1,21 @@
|
|||
MIT 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.
|
|
@ -0,0 +1 @@
|
|||
graft docs/examples/
|
|
@ -0,0 +1,357 @@
|
|||
Metadata-Version: 2.1
|
||||
Name: pkginfo
|
||||
Version: 1.8.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: ``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 <http://packages.python.org/pkginfo>`_
|
||||
for detailed documentation.
|
||||
|
||||
|
||||
``pkginfo`` Changelog
|
||||
=====================
|
||||
|
||||
1.8.2 (2021-12-01)
|
||||
------------------
|
||||
|
||||
- Add fix for installed distributions with '__package__' set to an empty
|
||||
string. LP #1952946.
|
||||
|
||||
1.8.1 (2021-11-19)
|
||||
------------------
|
||||
|
||||
- Add 'MANIFEST.in' to ensure example files used by tests are included
|
||||
in source distributions. LP #1951553.
|
||||
|
||||
1.8.0 (2021-11-18)
|
||||
------------------
|
||||
|
||||
- Support new standard metadata location for installed dists. LP #1865286.
|
||||
|
||||
- Don't overwrite header-based 'description' with empty payload. LP #1885458.
|
||||
|
||||
- Add support for Metadata-Version 2.2. LP #1928729.
|
||||
|
||||
- Add support for uncompressed tarballs for sdists. LP #1951457.
|
||||
|
||||
- Add support for Python 3.10.
|
||||
|
||||
1.7.1 (2021-07-09)
|
||||
------------------
|
||||
|
||||
- Use Python3 to build docs, and fix doctest examples to use Python3-
|
||||
compatible syntax. LP #1933322.
|
||||
|
||||
1.7.0 (2021-01-16)
|
||||
------------------
|
||||
|
||||
- Add support for Python 3.9.
|
||||
|
||||
- Drop support for Python 3.5.
|
||||
|
||||
1.6.1 (2020-10-26)
|
||||
------------------
|
||||
|
||||
- Adjust test classifiers to match supported Python versions. LP #1901127.
|
||||
|
||||
1.6.0 (2020-10-20)
|
||||
------------------
|
||||
|
||||
- Add support for Python 3.8.
|
||||
LP #1869854.
|
||||
|
||||
- Drop support for Python 3.4.
|
||||
|
||||
- Update tests to match setuptools' change, no longer reporting metadata
|
||||
version for installed packages w/o explicit metadata. LP #1870197.
|
||||
|
||||
1.5.0.1 (2019-01-08)
|
||||
--------------------
|
||||
|
||||
- Fix broken 'sdist'. LP #1639585.
|
||||
|
||||
1.5.0 (2019-01-07)
|
||||
------------------
|
||||
|
||||
- Fix 'console_scripts' entry point syntax. LP #1810734.
|
||||
|
||||
- Add support for JSON output from the CLI. LP #1700580.
|
||||
|
||||
- Add support for installed wheels. E.g., 'dist-info/' dirs. LP #1700200.
|
||||
|
||||
- Harden metadata extraction against unexpected encodings. LP #1780454.
|
||||
|
||||
- Update tests to match pip/setuptools' use of new metadata version.
|
||||
LP #1772274.
|
||||
|
||||
- Add support for Python 3.6 and 3.7.
|
||||
|
||||
- Drop support for Python 3.3.
|
||||
|
||||
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.6
|
||||
Classifier: Programming Language :: Python :: 3.7
|
||||
Classifier: Programming Language :: Python :: 3.8
|
||||
Classifier: Programming Language :: Python :: 3.9
|
||||
Classifier: Programming Language :: Python :: 3.10
|
||||
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||
Classifier: Topic :: System :: Software Distribution
|
||||
Provides-Extra: testing
|
|
@ -0,0 +1,13 @@
|
|||
``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 <http://packages.python.org/pkginfo>`_
|
||||
for detailed documentation.
|
|
@ -0,0 +1,15 @@
|
|||
TODOs
|
||||
=====
|
||||
|
||||
- [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.
|
|
@ -0,0 +1,75 @@
|
|||
# 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 <target>' where <target> 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."
|
|
@ -0,0 +1,194 @@
|
|||
# -*- 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
|
||||
# "<project> v<release> 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/<name>.
|
||||
#html_copy_source = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> 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', u'pkginfo Documentation', u'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
|
|
@ -0,0 +1,164 @@
|
|||
Distribution 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 <metadata.html>`_ 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.
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,15 @@
|
|||
Metadata-Version: 2.0
|
||||
Name: mypackage
|
||||
Version: 0.1
|
||||
Summary: UNKNOWN
|
||||
Home-page: http://pypi.python.org/pypi/pkginfo
|
||||
Author: Tres Seaver
|
||||
Author-email: tseaver@palladion.com
|
||||
License: UNKNOWN
|
||||
Platform: UNKNOWN
|
||||
Classifier: Development Status :: 4 - Beta
|
||||
Classifier: Environment :: Console (Text Based)
|
||||
|
||||
UNKNOWN
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,12 @@
|
|||
Metadata-Version: 1.0
|
||||
Name: mypackage
|
||||
Version: 0.1
|
||||
Summary: UNKNOWN
|
||||
Home-page: http://pypi.python.org/pypi/pkginfo
|
||||
Author: Tres Seaver
|
||||
Author-email: tseaver@palladion.com
|
||||
License: UNKNOWN
|
||||
Description: UNKNOWN
|
||||
Platform: UNKNOWN
|
||||
Classifier: Development Status :: 4 - Beta
|
||||
Classifier: Environment :: Console (Text Based)
|
|
@ -0,0 +1,4 @@
|
|||
mypackage README
|
||||
================
|
||||
|
||||
Dummy package for testing ``pkginfo``.
|
|
@ -0,0 +1,5 @@
|
|||
[egg_info]
|
||||
tag_build =
|
||||
tag_date = 0
|
||||
tag_svn_revision = 0
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name='mypackage',
|
||||
version='0.1',
|
||||
author='Tres Seaver',
|
||||
author_email='tseaver@palladion.com',
|
||||
url='http://pypi.python.org/pypi/pkginfo',
|
||||
classifiers=[
|
||||
'Development Status :: 4 - Beta',
|
||||
'Environment :: Console (Text Based)',
|
||||
],
|
||||
)
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,18 @@
|
|||
: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
|
|
@ -0,0 +1,26 @@
|
|||
Distribution 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']
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
Metadata 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
|
|
@ -0,0 +1,357 @@
|
|||
Metadata-Version: 2.1
|
||||
Name: pkginfo
|
||||
Version: 1.8.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: ``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 <http://packages.python.org/pkginfo>`_
|
||||
for detailed documentation.
|
||||
|
||||
|
||||
``pkginfo`` Changelog
|
||||
=====================
|
||||
|
||||
1.8.2 (2021-12-01)
|
||||
------------------
|
||||
|
||||
- Add fix for installed distributions with '__package__' set to an empty
|
||||
string. LP #1952946.
|
||||
|
||||
1.8.1 (2021-11-19)
|
||||
------------------
|
||||
|
||||
- Add 'MANIFEST.in' to ensure example files used by tests are included
|
||||
in source distributions. LP #1951553.
|
||||
|
||||
1.8.0 (2021-11-18)
|
||||
------------------
|
||||
|
||||
- Support new standard metadata location for installed dists. LP #1865286.
|
||||
|
||||
- Don't overwrite header-based 'description' with empty payload. LP #1885458.
|
||||
|
||||
- Add support for Metadata-Version 2.2. LP #1928729.
|
||||
|
||||
- Add support for uncompressed tarballs for sdists. LP #1951457.
|
||||
|
||||
- Add support for Python 3.10.
|
||||
|
||||
1.7.1 (2021-07-09)
|
||||
------------------
|
||||
|
||||
- Use Python3 to build docs, and fix doctest examples to use Python3-
|
||||
compatible syntax. LP #1933322.
|
||||
|
||||
1.7.0 (2021-01-16)
|
||||
------------------
|
||||
|
||||
- Add support for Python 3.9.
|
||||
|
||||
- Drop support for Python 3.5.
|
||||
|
||||
1.6.1 (2020-10-26)
|
||||
------------------
|
||||
|
||||
- Adjust test classifiers to match supported Python versions. LP #1901127.
|
||||
|
||||
1.6.0 (2020-10-20)
|
||||
------------------
|
||||
|
||||
- Add support for Python 3.8.
|
||||
LP #1869854.
|
||||
|
||||
- Drop support for Python 3.4.
|
||||
|
||||
- Update tests to match setuptools' change, no longer reporting metadata
|
||||
version for installed packages w/o explicit metadata. LP #1870197.
|
||||
|
||||
1.5.0.1 (2019-01-08)
|
||||
--------------------
|
||||
|
||||
- Fix broken 'sdist'. LP #1639585.
|
||||
|
||||
1.5.0 (2019-01-07)
|
||||
------------------
|
||||
|
||||
- Fix 'console_scripts' entry point syntax. LP #1810734.
|
||||
|
||||
- Add support for JSON output from the CLI. LP #1700580.
|
||||
|
||||
- Add support for installed wheels. E.g., 'dist-info/' dirs. LP #1700200.
|
||||
|
||||
- Harden metadata extraction against unexpected encodings. LP #1780454.
|
||||
|
||||
- Update tests to match pip/setuptools' use of new metadata version.
|
||||
LP #1772274.
|
||||
|
||||
- Add support for Python 3.6 and 3.7.
|
||||
|
||||
- Drop support for Python 3.3.
|
||||
|
||||
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.6
|
||||
Classifier: Programming Language :: Python :: 3.7
|
||||
Classifier: Programming Language :: Python :: 3.8
|
||||
Classifier: Programming Language :: Python :: 3.9
|
||||
Classifier: Programming Language :: Python :: 3.10
|
||||
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||
Classifier: Topic :: System :: Software Distribution
|
||||
Provides-Extra: testing
|
|
@ -0,0 +1,71 @@
|
|||
.bzrignore
|
||||
.coveragerc
|
||||
CHANGES.txt
|
||||
LICENSE.txt
|
||||
MANIFEST.in
|
||||
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/distlib-0.3.1-py2.py3-none-any.whl
|
||||
docs/examples/mypackage-0.1-cp26-none-linux_x86_64.whl
|
||||
docs/examples/mypackage-0.1-py2.6.egg
|
||||
docs/examples/mypackage-0.1.bogus
|
||||
docs/examples/mypackage-0.1.tar
|
||||
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
|
||||
docs/examples/mypackage-0.1.dist-info/METADATA
|
||||
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__.py
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
[console_scripts]
|
||||
pkginfo = pkginfo.commandline:main
|
||||
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
[testing]
|
||||
coverage
|
||||
nose
|
|
@ -0,0 +1 @@
|
|||
pkginfo
|
|
@ -0,0 +1,9 @@
|
|||
from .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
|
|
@ -0,0 +1,34 @@
|
|||
try:
|
||||
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
|
|
@ -0,0 +1,39 @@
|
|||
import 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)
|
||||
|
|
@ -0,0 +1,232 @@
|
|||
"""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 this case, 'path' should point to a directory
|
||||
initialized 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 collections import OrderedDict
|
||||
from csv import writer
|
||||
import json
|
||||
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",
|
||||
)
|
||||
|
||||
parser.add_option("--json", dest="output", action="store_const",
|
||||
const='json',
|
||||
help="Output as JSON",
|
||||
)
|
||||
|
||||
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
|
||||
|
||||
class JSON(Base):
|
||||
_fields = None
|
||||
def __init__(self, options):
|
||||
super(JSON, self).__init__(options)
|
||||
self._mapping = OrderedDict()
|
||||
|
||||
def __call__(self, meta):
|
||||
if self._fields is None:
|
||||
self._fields = list(meta)
|
||||
for field in self._fields:
|
||||
value = getattr(meta, field)
|
||||
if value and not isinstance(value, (tuple, list)):
|
||||
value = str(value)
|
||||
if field in self._mapping:
|
||||
raise ValueError('Duplicate field: %(field)r' % locals())
|
||||
self._mapping[field] = value
|
||||
|
||||
def finish(self):
|
||||
json.dump(self._mapping, sys.stdout, indent=2)
|
||||
|
||||
_FORMATTERS = {
|
||||
'simple': Simple,
|
||||
'single': SingleLine,
|
||||
'csv': CSV,
|
||||
'ini': INI,
|
||||
'json': JSON,
|
||||
}
|
||||
|
||||
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()
|
|
@ -0,0 +1,46 @@
|
|||
import io
|
||||
import 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 io.open(path, errors='ignore') as f:
|
||||
return f.read()
|
||||
warnings.warn('No PKG-INFO found for path: %s' % self.path)
|
|
@ -0,0 +1,154 @@
|
|||
from 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_2_2 = HEADER_ATTRS_2_1 + ( # PEP 643
|
||||
('Dynamic', 'dynamic', True),
|
||||
)
|
||||
|
||||
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,
|
||||
'2.2': HEADER_ATTRS_2_2,
|
||||
}
|
||||
|
||||
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
|
||||
# version 2.2
|
||||
dynamic = ()
|
||||
|
||||
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__
|
|
@ -0,0 +1,15 @@
|
|||
from .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 <name>-<version>.')
|
||||
super(Index, self).__setitem__(key, value)
|
||||
|
||||
def add(self, distribution):
|
||||
key = '%s-%s' % (distribution.name, distribution.version)
|
||||
self[key] = distribution
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
import glob
|
||||
import io
|
||||
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 in ('', None):
|
||||
package = self.package.__name__
|
||||
egg_pattern = '%s*.egg-info' % package
|
||||
dist_pattern = '%s*.dist-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, egg_pattern))
|
||||
_add_candidate(opj(entry, dist_pattern))
|
||||
dir, name = os.path.split(self.package.__file__)
|
||||
_add_candidate(opj(dir, egg_pattern))
|
||||
_add_candidate(opj(dir, '..', egg_pattern))
|
||||
_add_candidate(opj(dir, dist_pattern))
|
||||
_add_candidate(opj(dir, '..', dist_pattern))
|
||||
for candidate in candidates:
|
||||
if os.path.isdir(candidate):
|
||||
if candidate.lower().endswith("egg-info"):
|
||||
path = opj(candidate, 'PKG-INFO')
|
||||
elif candidate.endswith("dist-info"):
|
||||
path = opj(candidate, 'METADATA')
|
||||
else: # pragma: NO COVER
|
||||
continue
|
||||
else:
|
||||
path = candidate
|
||||
if os.path.exists(path):
|
||||
with io.open(path, errors='ignore') as f:
|
||||
return f.read()
|
||||
warnings.warn('No PKG-INFO found for package: %s' % self.package_name)
|
|
@ -0,0 +1,75 @@
|
|||
import io
|
||||
import 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 zipfile.is_zipfile(fqn):
|
||||
archive = zipfile.ZipFile(fqn)
|
||||
names = archive.namelist()
|
||||
def read_file(name):
|
||||
return archive.read(name)
|
||||
elif tarfile.is_tarfile(fqn):
|
||||
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:
|
||||
pkg_info = os.path.join(self.filename, 'PKG-INFO')
|
||||
with io.open(pkg_info, errors='ignore') as f:
|
||||
return f.read()
|
||||
except Exception as e:
|
||||
raise ValueError('Could not load %s as an unpacked sdist: %s'
|
||||
% (self.filename, e))
|
|
@ -0,0 +1,37 @@
|
|||
# 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.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Programming Language :: Python :: 3.9',
|
||||
'Programming Language :: Python :: 3.10',
|
||||
'Programming Language :: Python :: Implementation :: CPython',
|
||||
'Programming Language :: Python :: Implementation :: PyPy',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||
'Topic :: System :: Software Distribution',
|
||||
])
|
||||
|
||||
|
||||
def _defaultMetadataVersion():
|
||||
return '2.1'
|
|
@ -0,0 +1,2 @@
|
|||
# sample installed package w/ .egg-info file.
|
||||
__package__ = 'funny'
|
|
@ -0,0 +1,3 @@
|
|||
Metadata-Version: 1.0
|
||||
Name: funny
|
||||
Version: 0.1
|
|
@ -0,0 +1,4 @@
|
|||
THIS IS NOT A PYTHON PACKAGE!!!!
|
||||
|
||||
It is meant to be added to sys.path for testing introspection of namespace
|
||||
packages installed via setuptools.
|
|
@ -0,0 +1,2 @@
|
|||
Metadata-Version: 1.0
|
||||
Name: namespaced.wonky
|
|
@ -0,0 +1,7 @@
|
|||
# this is a namespace package
|
||||
try:
|
||||
import pkg_resources
|
||||
pkg_resources.declare_namespace(__name__)
|
||||
except ImportError:
|
||||
import pkgutil
|
||||
__path__ = pkgutil.extend_path(__path__, __name__)
|
|
@ -0,0 +1 @@
|
|||
# Dummy package inside the 'namespaced' namespace.
|
|
@ -0,0 +1,3 @@
|
|||
Metadata-Version: 1.0
|
||||
Name: silly
|
||||
Version: 0.1
|
|
@ -0,0 +1,60 @@
|
|||
import 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)
|
|
@ -0,0 +1,350 @@
|
|||
import 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 JSONtests(unittest.TestCase, _FormatterBase):
|
||||
|
||||
def _getTargetClass(self):
|
||||
from pkginfo.commandline import JSON
|
||||
return JSON
|
||||
|
||||
def _makeOne(self, options):
|
||||
return self._getTargetClass()(options)
|
||||
|
||||
def test___call___duplicate_with_meta_and_fields(self):
|
||||
json = self._makeOne(_Options(fields=('name',)))
|
||||
meta = _Meta(name='foo', version='0.1', foo='Foo')
|
||||
json._mapping['name'] = 'foo'
|
||||
self.assertRaises(ValueError, json, meta)
|
||||
|
||||
def test___call___duplicate_with_meta_wo_fields(self):
|
||||
json = self._makeOne(_Options(fields=None))
|
||||
meta = _Meta(name='foo', version='0.1', foo='Foo')
|
||||
json._mapping['name'] = 'foo'
|
||||
self.assertRaises(ValueError, json, meta)
|
||||
|
||||
def test___call___wo_fields_wo_list(self):
|
||||
from collections import OrderedDict
|
||||
|
||||
json = self._makeOne(_Options(fields=None))
|
||||
meta = _Meta(name='foo', version='0.1', foo='Foo')
|
||||
json(meta)
|
||||
expected = OrderedDict([
|
||||
('foo', 'Foo'), ('name', 'foo'), ('version', '0.1')])
|
||||
self.assertEqual(expected, json._mapping)
|
||||
|
||||
def test___call___w_fields_w_list(self):
|
||||
from collections import OrderedDict
|
||||
|
||||
json = self._makeOne(_Options(fields=('foo', 'bar')))
|
||||
meta = _Meta(name='foo', version='0.1',
|
||||
foo='Foo', bar=['Bar1', 'Bar2'], baz='Baz')
|
||||
json(meta)
|
||||
expected = OrderedDict([
|
||||
('foo', 'Foo'), ('bar', ['Bar1', 'Bar2'])])
|
||||
self.assertEqual(expected, json._mapping)
|
||||
|
||||
def test___call___output(self):
|
||||
from collections import OrderedDict
|
||||
import json as json_parser
|
||||
|
||||
json = self._makeOne(_Options(fields=None))
|
||||
meta = _Meta(name='foo', version='0.1', foo='Foo')
|
||||
json(meta)
|
||||
output = self._capture_output(json.finish)
|
||||
output = json_parser.loads(
|
||||
output, object_pairs_hook=OrderedDict)
|
||||
expected = OrderedDict([
|
||||
('foo', 'Foo'), ('name', 'foo'), ('version', '0.1')])
|
||||
self.assertEqual(expected, output)
|
||||
|
||||
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
|
|
@ -0,0 +1,27 @@
|
|||
import 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
|
|
@ -0,0 +1,450 @@
|
|||
import 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)
|
||||
# version 1.0
|
||||
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)
|
||||
# version 1.1
|
||||
self.assertEqual(sdist.classifiers, ())
|
||||
self.assertEqual(sdist.requires, ())
|
||||
self.assertEqual(sdist.provides, ())
|
||||
self.assertEqual(sdist.obsoletes, ())
|
||||
# version 1.2
|
||||
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, ())
|
||||
# version 2.1
|
||||
self.assertEqual(sdist.provides_extras, ())
|
||||
self.assertEqual(sdist.description_content_type, None)
|
||||
# version 2.2
|
||||
self.assertEqual(sdist.dynamic, ())
|
||||
|
||||
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_given_unicode(self):
|
||||
from pkginfo._compat import u
|
||||
dist = self._makeOne()
|
||||
dist.parse(u('Metadata-Version: 1.0\nName: lp722928_c3')) # no raise
|
||||
|
||||
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_2_2(self):
|
||||
from pkginfo.distribution import HEADER_ATTRS_2_2
|
||||
dist = self._makeOne(None)
|
||||
dist.parse('Metadata-Version: 2.2')
|
||||
self.assertEqual(dist.metadata_version, '2.2')
|
||||
self.assertEqual(list(dist),
|
||||
[x[1] for x in HEADER_ATTRS_2_2])
|
||||
|
||||
def test_parse_Metadata_Version_unknown(self):
|
||||
dist = self._makeOne(None)
|
||||
dist.parse('Metadata-Version: 1.3')
|
||||
self.assertEqual(dist.metadata_version, '1.3')
|
||||
self.assertEqual(list(dist), [])
|
||||
|
||||
def test_parse_Metadata_Version_override(self):
|
||||
dist = self._makeOne('1.2')
|
||||
dist.parse('Metadata-Version: 1.0')
|
||||
self.assertEqual(dist.metadata_version, '1.2')
|
||||
|
||||
def test_parse_Name(self):
|
||||
dist = self._makeOne()
|
||||
dist.parse('Name: foobar')
|
||||
self.assertEqual(dist.name, 'foobar')
|
||||
|
||||
def test_parse_Version(self):
|
||||
dist = self._makeOne()
|
||||
dist.parse('Version: 2.1.3b5')
|
||||
self.assertEqual(dist.version, '2.1.3b5')
|
||||
|
||||
def test_parse_Platform_single(self):
|
||||
dist = self._makeOne()
|
||||
dist.parse('Platform: Plan9')
|
||||
self.assertEqual(list(dist.platforms), ['Plan9'])
|
||||
|
||||
def test_parse_Platform_multiple(self):
|
||||
dist = self._makeOne()
|
||||
dist.parse('Platform: Plan9\nPlatform: AIX')
|
||||
self.assertEqual(list(dist.platforms), ['Plan9', 'AIX'])
|
||||
|
||||
def test_parse_Supported_Platform_single(self):
|
||||
dist = self._makeOne()
|
||||
dist.parse('Supported-Platform: Plan9')
|
||||
self.assertEqual(list(dist.supported_platforms), ['Plan9'])
|
||||
|
||||
def test_parse_Supported_Platform_multiple(self):
|
||||
dist = self._makeOne()
|
||||
dist.parse('Supported-Platform: i386-win32\n'
|
||||
'Supported-Platform: RedHat 7.2')
|
||||
self.assertEqual(list(dist.supported_platforms),
|
||||
['i386-win32', 'RedHat 7.2'])
|
||||
|
||||
def test_parse_Summary(self):
|
||||
dist = self._makeOne()
|
||||
dist.parse('Summary: Package for foo')
|
||||
self.assertEqual(dist.summary, 'Package for foo')
|
||||
|
||||
def test_parse_Description(self):
|
||||
dist = self._makeOne()
|
||||
dist.parse('Description: This package enables integration with '
|
||||
'foo servers.')
|
||||
self.assertEqual(dist.description,
|
||||
'This package enables integration with '
|
||||
'foo servers.')
|
||||
|
||||
def test_parse_Description_multiline(self):
|
||||
dist = self._makeOne()
|
||||
dist.parse('Description: This package enables integration with\n'
|
||||
' foo servers.')
|
||||
self.assertEqual(dist.description,
|
||||
'This package enables integration with\n'
|
||||
'foo servers.')
|
||||
|
||||
def test_parse_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',
|
||||
])
|
||||
|
||||
# Metadata version 2.1, defined in PEP 566.
|
||||
def test_parse_Provides_Extra_single(self):
|
||||
dist = self._makeOne('2.1')
|
||||
dist.parse('Provides-Extra: pdf')
|
||||
self.assertEqual(list(dist.provides_extras), ['pdf'])
|
||||
|
||||
def test_parse_Provides_Extra_multiple(self):
|
||||
dist = self._makeOne('2.1')
|
||||
dist.parse('Provides-Extra: pdf\n'
|
||||
'Provides-Extra: tex')
|
||||
self.assertEqual(list(dist.provides_extras), ['pdf', 'tex'])
|
||||
|
||||
def test_parse_Provides_Extra_single(self):
|
||||
dist = self._makeOne('2.1')
|
||||
dist.parse('Description-Content-Type: text/plain')
|
||||
self.assertEqual(dist.description_content_type, 'text/plain')
|
||||
|
||||
# Metadata version 2.2, defined in PEP 643.
|
||||
def test_parse_Dynamic_single(self):
|
||||
dist = self._makeOne('2.2')
|
||||
dist.parse('Dynamic: Platforms')
|
||||
self.assertEqual(list(dist.dynamic), ['Platforms'])
|
||||
|
||||
def test_parse_Dynamic_multiple(self):
|
||||
dist = self._makeOne('2.2')
|
||||
dist.parse('Dynamic: Platforms\n'
|
||||
'Dynamic: Supported-Platforms')
|
||||
self.assertEqual(list(dist.dynamic),
|
||||
['Platforms', 'Supported-Platforms'])
|
|
@ -0,0 +1,76 @@
|
|||
import 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))
|
|
@ -0,0 +1,142 @@
|
|||
import 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')
|
||||
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_ctor_w_dist_info(self):
|
||||
import wheel
|
||||
installed = self._makeOne('wheel')
|
||||
self.assertEqual(installed.metadata_version, '2.1')
|
||||
self.assertEqual(installed.package, wheel)
|
||||
self.assertEqual(installed.package_name, 'wheel')
|
||||
|
||||
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)
|
|
@ -0,0 +1,158 @@
|
|||
import 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_tar(self):
|
||||
import os
|
||||
d, _ = os.path.split(__file__)
|
||||
filename = '%s/../../docs/examples/mypackage-0.1.tar' % d
|
||||
sdist = self._makeOne(filename)
|
||||
self.assertEqual(sdist.metadata_version, '1.0')
|
||||
self._checkSample(sdist, 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)
|
||||
|
||||
def test_ctor_w_bogus(self):
|
||||
import os
|
||||
d, _ = os.path.split(__file__)
|
||||
filename = '%s/../../docs/examples/mypackage-0.1.bogus' % d
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
self._makeOne(filename, metadata_version='1.1')
|
||||
|
||||
|
||||
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')
|
|
@ -0,0 +1,176 @@
|
|||
import 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')
|
|
@ -0,0 +1,105 @@
|
|||
import 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_installed_wheel(self):
|
||||
import os
|
||||
d, _ = os.path.split(__file__)
|
||||
filename = (
|
||||
'%s/../../docs/examples/mypackage-0.1.dist-info') % 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)
|
||||
|
||||
def test_ctor_w_valid_wheel_w_description_header(self):
|
||||
import os
|
||||
d, _ = os.path.split(__file__)
|
||||
filename = ('%s/../../docs/examples/'
|
||||
'distlib-0.3.1-py2.py3-none-any.whl') % d
|
||||
wheel = self._makeOne(filename, metadata_version='1.1')
|
||||
self.assertEqual(wheel.metadata_version, '1.1')
|
||||
self.assertTrue(wheel.description)
|
||||
|
||||
def test_ctor_w_valid_installed_wheel(self):
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
import zipfile
|
||||
|
||||
d, _ = os.path.split(__file__)
|
||||
filename = ('%s/../../docs/examples/'
|
||||
'mypackage-0.1-cp26-none-linux_x86_64.whl') % d
|
||||
|
||||
try:
|
||||
# note: we mock a wheel installation by unzipping
|
||||
test_dir = tempfile.mkdtemp()
|
||||
with zipfile.ZipFile(filename) as zipf:
|
||||
zipf.extractall(test_dir)
|
||||
wheel = self._makeOne(filename)
|
||||
self.assertEqual(wheel.metadata_version, '2.0')
|
||||
self._checkSample(wheel, filename)
|
||||
self._checkClassifiers(wheel)
|
||||
finally:
|
||||
if os.path.exists(test_dir):
|
||||
shutil.rmtree(test_dir)
|
|
@ -0,0 +1,2 @@
|
|||
Metadata-Version: 1.0
|
||||
Name: namespaced.wonky
|
|
@ -0,0 +1,4 @@
|
|||
THIS IS NOT A PYTHON PACKAGE!!!!
|
||||
|
||||
It is meant to be added to sys.path for testing introspection of namespace
|
||||
packages installed via setuptools.
|
|
@ -0,0 +1,7 @@
|
|||
# this is a namespace package
|
||||
try:
|
||||
import pkg_resources
|
||||
pkg_resources.declare_namespace(__name__)
|
||||
except ImportError:
|
||||
import pkgutil
|
||||
__path__ = pkgutil.extend_path(__path__, __name__)
|
|
@ -0,0 +1 @@
|
|||
# Dummy package inside the 'namespaced' namespace.
|
|
@ -0,0 +1,62 @@
|
|||
import 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 Wheel(path_or_module, metadata_version)
|
||||
except (ValueError, IOError): #pragma NO COVER
|
||||
pass
|
||||
|
||||
try:
|
||||
return Develop(path_or_module, metadata_version)
|
||||
except (ValueError, IOError): #pragma NO COVER
|
||||
pass
|
|
@ -0,0 +1,63 @@
|
|||
import io
|
||||
import os
|
||||
import zipfile
|
||||
|
||||
|
||||
from .distribution import Distribution
|
||||
from .distribution import must_decode
|
||||
from .distribution import parse
|
||||
|
||||
|
||||
class Wheel(Distribution):
|
||||
|
||||
def __init__(self, filename, metadata_version=None):
|
||||
self.filename = filename
|
||||
self.metadata_version = metadata_version
|
||||
self.extractMetadata()
|
||||
|
||||
def read(self):
|
||||
fqn = os.path.abspath(os.path.normpath(self.filename))
|
||||
if not os.path.exists(fqn):
|
||||
raise ValueError('No such file: %s' % fqn)
|
||||
|
||||
if fqn.endswith('.whl'):
|
||||
archive = zipfile.ZipFile(fqn)
|
||||
names = archive.namelist()
|
||||
|
||||
def read_file(name):
|
||||
return archive.read(name)
|
||||
|
||||
close = archive.close
|
||||
|
||||
elif fqn.endswith('.dist-info'):
|
||||
names = [os.path.join(fqn, p) for p in os.listdir(fqn)]
|
||||
|
||||
def read_file(name):
|
||||
with io.open(name, mode='rb') as inf:
|
||||
return inf.read()
|
||||
|
||||
close = lambda : None
|
||||
|
||||
else:
|
||||
raise ValueError('Not a known wheel archive format or '
|
||||
'installed .dist-info: %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:
|
||||
close()
|
||||
|
||||
raise ValueError('No METADATA in archive: %s' % fqn)
|
||||
|
||||
def parse(self, data):
|
||||
super(Wheel, self).parse(data)
|
||||
fp = io.StringIO(must_decode(data))
|
||||
msg = parse(fp)
|
||||
if self.description is None:
|
||||
self.description = msg.get_payload()
|
|
@ -0,0 +1,18 @@
|
|||
[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
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
#!/usr/bin/env python
|
||||
import 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.8.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.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Programming Language :: Python :: 3.9',
|
||||
'Programming Language :: Python :: 3.10',
|
||||
'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
|
||||
)
|
|
@ -0,0 +1,37 @@
|
|||
[tox]
|
||||
envlist =
|
||||
py27,pypy,py36,py37,py38,py39,py310,pypy3,cover2,cover3,docs
|
||||
|
||||
[testenv]
|
||||
usedevelop = true
|
||||
commands =
|
||||
python setup.py test -q
|
||||
|
||||
[testenv:cover2]
|
||||
basepython =
|
||||
python2.7
|
||||
commands =
|
||||
python setup.py nosetests --with-xunit --with-xcoverage
|
||||
deps =
|
||||
nose
|
||||
coverage
|
||||
nosexcover
|
||||
|
||||
[testenv:cover3]
|
||||
basepython =
|
||||
python3.7
|
||||
commands =
|
||||
python setup.py nosetests --with-xunit --with-xcoverage
|
||||
deps =
|
||||
nose
|
||||
coverage
|
||||
nosexcover
|
||||
|
||||
[testenv:docs]
|
||||
basepython =
|
||||
python3.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
|
Loading…
Reference in New Issue