initial commit

This commit is contained in:
Davidson Gomes
2024-10-30 11:19:09 -03:00
commit 8654a31a4d
3744 changed files with 585542 additions and 0 deletions

View File

@@ -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

View File

@@ -0,0 +1,8 @@
from .bdist import BDist as BDist
from .develop import Develop as Develop
from .distribution import Distribution as Distribution
from .index import Index as Index
from .installed import Installed as Installed
from .sdist import SDist as SDist, UnpackedSDist as UnpackedSDist
from .utils import get_metadata as get_metadata
from .wheel import Wheel as Wheel

View File

@@ -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)

View File

@@ -0,0 +1,7 @@
from .distribution import Distribution as Distribution
class BDist(Distribution):
filename: str
metadata_version: str
def __init__(self, filename: str, metadata_version: str | None = ...) -> None: ...
def read(self) -> bytes: ...

View File

@@ -0,0 +1,229 @@
"""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.
"""
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()

View File

@@ -0,0 +1,35 @@
import optparse
from typing import List
from .distribution import Distribution
from .utils import get_metadata as get_metadata
ParsedOptions = tuple[optparse.Values, list[str]]
class Base:
def __init__(self, options: ParsedOptions) -> None: ...
def finish(self) -> None: ...
class Simple(Base):
def __init__(self, options: ParsedOptions) -> None: ...
def __call__(self, meta: Distribution) -> None: ...
class SingleLine(Base):
def __init__(self, options: ParsedOptions) -> None: ...
def __call__(self, meta: Distribution) -> None: ...
class CSV(Base):
def __init__(self, options: ParsedOptions) -> None: ...
def __call__(self, meta: Distribution) -> None: ...
class INI(Base):
def __init__(self, options: ParsedOptions) -> None: ...
def __call__(self, meta: Distribution) -> None: ...
def finish(self) -> None: ...
class JSON(Base):
def __init__(self, options: ParsedOptions) -> None: ...
def __call__(self, meta: Distribution) -> None: ...
def finish(self) -> None: ...
def main(args: List[str] | None = ...) -> None: ...

View File

@@ -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)

View File

@@ -0,0 +1,7 @@
from .distribution import Distribution as Distribution
class Develop(Distribution):
path: str
metadata_version: str
def __init__(self, path: str, metadata_version: str | None = ...) -> None: ...
def read(self) -> bytes: ...

View File

@@ -0,0 +1,165 @@
import io
from email.parser import Parser
def _must_decode(value):
if type(value) is bytes:
try:
return value.decode('utf-8')
except UnicodeDecodeError:
return value.decode('latin1')
return value
must_decode = _must_decode # deprecated compatibility alias FBO twine.
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_2_3 = HEADER_ATTRS_2_2 # PEP 685
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,
'2.3': HEADER_ATTRS_2_3,
}
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 = io.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__

View File

@@ -0,0 +1,57 @@
import email.message
from typing import Callable
from typing import Dict
from typing import Generator
from typing import List
from typing import Sequence
from typing import TextIO
from typing import Tuple
def parse(fp: TextIO) -> email.message.Message: ...
def get(msg: email.message.Message, header: str) -> str: ...
def get_all(msg: email.message.Message, header: str) -> List[str]: ...
_header_attr_triple = Tuple[str, str, bool]
_header_attrs = Tuple[_header_attr_triple]
HEADER_ATTRS_1_0: _header_attrs
HEADER_ATTRS_1_1: _header_attrs
HEADER_ATTRS_1_2: _header_attrs
HEADER_ATTRS_2_0 = HEADER_ATTRS_1_2
HEADER_ATTRS_2_1: _header_attrs
HEADER_ATTRS_2_2: _header_attrs
HEADER_ATTRS: Dict[str, _header_attrs]
class Distribution:
metadata_version: str | None
name: str
version: str
platforms: Sequence[str]
supported_platforms: Sequence[str]
summary: str
description: str
keywords: str
home_page: str
download_url: str
author: str
author_email: str
license: str
classifiers: Sequence[str]
requires: Sequence[str]
provides: Sequence[str]
obsoletes: Sequence[str]
maintainer: str
maintainer_email: str
requires_python: str
requires_external: Sequence[str]
requires_dist: Sequence[str]
provides_dist: Sequence[str]
obsoletes_dist: Sequence[str]
project_urls: Sequence[str]
provides_extras: Sequence[str]
description_content_type: str
dynamic: Sequence[str]
def extractMetadata(self) -> None: ...
def read(self) -> bytes: ...
def parse(self, data: bytes) -> None: ...
def __iter__(self) -> Generator[str, None, None]: ...
iterkeys: Generator[str, None, None]

View File

@@ -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

View File

@@ -0,0 +1,5 @@
from .distribution import Distribution as Distribution
class Index(dict[str, Distribution]):
def __setitem__(self, key: str, value: Distribution) -> None: ...
def add(self, distribution: Distribution) -> None: ...

View File

@@ -0,0 +1,62 @@
import glob
import io
import os
import sys
import warnings
from .distribution import Distribution
class Installed(Distribution):
def __init__(self, package, metadata_version=None):
if isinstance(package, str):
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
pkg_file = getattr(self.package, '__file__', None)
if pkg_file is not None:
candidates = []
def _add_candidate(where):
candidates.extend(glob.glob(where))
for entry in sys.path:
if pkg_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)

View File

@@ -0,0 +1,10 @@
import types
from .distribution import Distribution as Distribution
class Installed(Distribution):
package_name: str
package: str | types.ModuleType
metadata_version: str
def __init__(self, package: str | types.ModuleType, metadata_version: str | None = ...) -> None: ...
def read(self) -> bytes: ...

View File

View File

@@ -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))

View File

@@ -0,0 +1,11 @@
from .distribution import Distribution as Distribution
class SDist(Distribution):
filename: str
metadata_version: str
def __init__(self, filename: str, metadata_version: str | None = ...) -> None: ...
def read(self) -> bytes: ...
class UnpackedSDist(SDist):
def __init__(self, filename: str, metadata_version: str | None = ...) -> None: ...
def read(self) -> bytes: ...

View File

@@ -0,0 +1,37 @@
# requirements
def _checkSample(testcase, installed):
try:
from importlib import metadata as importlib_metadata
except ImportError: # python < 3.8
import importlib_metadata
version = importlib_metadata.version('pkginfo')
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 :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'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'

View File

@@ -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)

View File

@@ -0,0 +1,345 @@
import collections
import io
import json as json_module
import sys
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):
from pkginfo.commandline import __doc__ as usage
firstline = usage.splitlines()[0]
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):
buf = io.StringIO()
with _Monkey(sys, stdout=buf):
func(*args, **kw)
return buf.getvalue()
def _no_output(self, simple, meta):
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):
json = self._makeOne(_Options(fields=None))
meta = _Meta(name='foo', version='0.1', foo='Foo')
json(meta)
expected = collections.OrderedDict([
('foo', 'Foo'), ('name', 'foo'), ('version', '0.1')])
self.assertEqual(expected, json._mapping)
def test___call___w_fields_w_list(self):
json = self._makeOne(_Options(fields=('foo', 'bar')))
meta = _Meta(name='foo', version='0.1',
foo='Foo', bar=['Bar1', 'Bar2'], baz='Baz')
json(meta)
expected = collections.OrderedDict([
('foo', 'Foo'), ('bar', ['Bar1', 'Bar2'])])
self.assertEqual(expected, json._mapping)
def test___call___output(self):
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_module.loads(
output, object_pairs_hook=collections.OrderedDict)
expected = collections.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

View File

@@ -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

View File

@@ -0,0 +1,485 @@
import unittest
class Test__must_decode(unittest.TestCase):
def _callFUT(self, arg):
from pkginfo.distribution import _must_decode
return _must_decode(arg)
def test_w_bytes_latin1(self):
TO_ENCODE = u'\u00C9' # capital E w/ acute accent
encoded = TO_ENCODE.encode("latin-1")
decoded = self._callFUT(encoded)
self.assertEqual(decoded, TO_ENCODE)
def test_w_bytes_utf8(self):
TO_ENCODE = u'\u00C9' # capital E w/ acute accent
encoded = TO_ENCODE.encode("utf-8")
decoded = self._callFUT(encoded)
self.assertEqual(decoded, TO_ENCODE)
def test_w_unicode(self):
ARG = u'\u00C9' # capital E w/ acute accent
decoded = self._callFUT(ARG)
self.assertEqual(decoded, ARG)
def test_w_object(self):
ARG = object()
decoded = self._callFUT(ARG)
self.assertIs(decoded, ARG)
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):
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_2_3(self):
from pkginfo.distribution import HEADER_ATTRS_2_3
dist = self._makeOne(None)
dist.parse('Metadata-Version: 2.3')
self.assertEqual(dist.metadata_version, '2.3')
self.assertEqual(list(dist),
[x[1] for x in HEADER_ATTRS_2_3])
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_Distribution_Content_Type_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'])

View File

@@ -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))

View File

@@ -0,0 +1,141 @@
import os
import sys
import types
import unittest
import wsgiref
import warnings
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):
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):
with warnings.catch_warnings(record=True):
installed = self._makeOne(wsgiref)
self.assertEqual(installed.package, wsgiref)
self.assertEqual(installed.package_name, 'wsgiref')
self.assertEqual(installed.metadata_version, None)
def test_ctor_w_package_no_PKG_INFO(self):
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):
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):
where, _ = os.path.split(__file__)
wonky = os.path.join(where, 'wonky')
oldpath = sys.path[:]
try:
sys.path.append(wonky)
with warnings.catch_warnings(record=True):
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
where, _ = os.path.split(__file__)
manky = os.path.join(where, 'manky')
oldpath = sys.path[:]
try:
sys.path.append(manky)
with warnings.catch_warnings(record=True):
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)

View File

@@ -0,0 +1,165 @@
import pathlib
import shutil
import sys
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)
assert len(topnames) == 1
return os.path.join(self.__tmpdir, topnames[0])
def _getLoadFilename(self):
return self._getTopDirectory()
def _makeOne(self, filename=None, metadata_version=None):
archive, _, _ = self._getTargetClass()._get_archive(filename)
# Work around Python 3.12 tarfile warning.
kwargs = {}
if sys.version_info >= (3, 12):
fn_path = pathlib.Path(filename)
if ".tar" in fn_path.suffixes:
kwargs["filter"] = "data"
try:
archive.extractall(self.__tmpdir, **kwargs)
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')

View File

@@ -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')

View File

@@ -0,0 +1,117 @@
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_wheel_w_description_body(self):
import os
d, _ = os.path.split(__file__)
filename = ('%s/../../docs/examples/'
'testlp1974172-0.0.0-py3-none-any.whl') % d
wheel = self._makeOne(filename, metadata_version='2.1')
self.assertEqual(wheel.metadata_version, '2.1')
self.assertIn(
"https://bugs.launchpad.net/pkginfo/+bug/1885458",
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)

View File

@@ -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

View File

@@ -0,0 +1,5 @@
import types
from .distribution import Distribution
def get_metadata(path_or_module: str | types.ModuleType, metadata_version: str | None = ...) -> Distribution | None: ...

View File

@@ -0,0 +1,55 @@
import io
import os
import zipfile
from .distribution import Distribution
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)

View File

@@ -0,0 +1,7 @@
from .distribution import Distribution as Distribution, parse as parse
class Wheel(Distribution):
filename: str
metadata_version: str
def __init__(self, filename: str, metadata_version: str | None = ...) -> None: ...
def read(self) -> bytes: ...