evolution-client-python/env/lib/python3.10/site-packages/pkginfo/commandline.py
2024-10-30 11:19:09 -03:00

230 lines
7.2 KiB
Python

"""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()