Mercurial > public > mercurial-scm > hg-stable
diff mercurial/formatter.py @ 43076:2372284d9457
formatting: blacken the codebase
This is using my patch to black
(https://github.com/psf/black/pull/826) so we don't un-wrap collection
literals.
Done with:
hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S
# skip-blame mass-reformatting only
# no-check-commit reformats foo_bar functions
Differential Revision: https://phab.mercurial-scm.org/D6971
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 06 Oct 2019 09:45:02 -0400 |
parents | 77ef3498ceb3 |
children | 687b865b95ad |
line wrap: on
line diff
--- a/mercurial/formatter.py Sat Oct 05 10:29:34 2019 -0400 +++ b/mercurial/formatter.py Sun Oct 06 09:45:02 2019 -0400 @@ -116,9 +116,7 @@ hex, short, ) -from .thirdparty import ( - attr, -) +from .thirdparty import attr from . import ( error, @@ -137,6 +135,7 @@ pickle = util.pickle + class _nullconverter(object): '''convert non-primitive data types to be processed by formatter''' @@ -147,23 +146,27 @@ def wrapnested(data, tmpl, sep): '''wrap nested data by appropriate type''' return data + @staticmethod def formatdate(date, fmt): '''convert date tuple to appropriate format''' # timestamp can be float, but the canonical form should be int ts, tz = date return (int(ts), tz) + @staticmethod def formatdict(data, key, value, fmt, sep): '''convert dict or key-value pairs to appropriate dict format''' # use plain dict instead of util.sortdict so that data can be # serialized as a builtin dict in pickle output return dict(data) + @staticmethod def formatlist(data, name, fmt, sep): '''convert iterable to appropriate list format''' return list(data) + class baseformatter(object): def __init__(self, ui, topic, opts, converter): self._ui = ui @@ -173,29 +176,37 @@ self._item = None # function to convert node to string suitable for this output self.hexfunc = hex + def __enter__(self): return self + def __exit__(self, exctype, excvalue, traceback): if exctype is None: self.end() + def _showitem(self): '''show a formatted item once all data is collected''' + def startitem(self): '''begin an item in the format list''' if self._item is not None: self._showitem() self._item = {} + def formatdate(self, date, fmt='%a %b %d %H:%M:%S %Y %1%2'): '''convert date tuple to appropriate format''' return self._converter.formatdate(date, fmt) + def formatdict(self, data, key='key', value='value', fmt=None, sep=' '): '''convert dict or key-value pairs to appropriate dict format''' return self._converter.formatdict(data, key, value, fmt, sep) + def formatlist(self, data, name, fmt=None, sep=' '): '''convert iterable to appropriate list format''' # name is mandatory argument for now, but it could be optional if # we have default template keyword, e.g. {item} return self._converter.formatlist(data, name, fmt, sep) + def context(self, **ctxs): '''insert context objects to be used to render template keywords''' ctxs = pycompat.byteskwargs(ctxs) @@ -207,56 +218,70 @@ if 'ctx' in ctxs and 'repo' not in ctxs: ctxs['repo'] = ctxs['ctx'].repo() self._item.update(ctxs) + def datahint(self): '''set of field names to be referenced''' return set() + def data(self, **data): '''insert data into item that's not shown in default output''' data = pycompat.byteskwargs(data) self._item.update(data) + def write(self, fields, deftext, *fielddata, **opts): '''do default text output while assigning data to item''' fieldkeys = fields.split() assert len(fieldkeys) == len(fielddata), (fieldkeys, fielddata) self._item.update(zip(fieldkeys, fielddata)) + def condwrite(self, cond, fields, deftext, *fielddata, **opts): '''do conditional write (primarily for plain formatter)''' fieldkeys = fields.split() assert len(fieldkeys) == len(fielddata) self._item.update(zip(fieldkeys, fielddata)) + def plain(self, text, **opts): '''show raw text for non-templated mode''' + def isplain(self): '''check for plain formatter usage''' return False + def nested(self, field, tmpl=None, sep=''): '''sub formatter to store nested data in the specified field''' data = [] self._item[field] = self._converter.wrapnested(data, tmpl, sep) return _nestedformatter(self._ui, self._converter, data) + def end(self): '''end output for the formatter''' if self._item is not None: self._showitem() + def nullformatter(ui, topic, opts): '''formatter that prints nothing''' return baseformatter(ui, topic, opts, converter=_nullconverter) + class _nestedformatter(baseformatter): '''build sub items and store them in the parent formatter''' + def __init__(self, ui, converter, data): baseformatter.__init__(self, ui, topic='', opts={}, converter=converter) self._data = data + def _showitem(self): self._data.append(self._item) + def _iteritems(data): '''iterate key-value pairs in stable order''' if isinstance(data, dict): return sorted(data.iteritems()) return data + class _plainconverter(object): '''convert non-primitive data types to text''' @@ -265,10 +290,12 @@ @staticmethod def wrapnested(data, tmpl, sep): raise error.ProgrammingError('plainformatter should never be nested') + @staticmethod def formatdate(date, fmt): '''stringify date tuple in the given format''' return dateutil.datestr(date, fmt) + @staticmethod def formatdict(data, key, value, fmt, sep): '''stringify key-value pairs separated by sep''' @@ -276,8 +303,10 @@ if fmt is None: fmt = '%s=%s' prefmt = pycompat.bytestr - return sep.join(fmt % (prefmt(k), prefmt(v)) - for k, v in _iteritems(data)) + return sep.join( + fmt % (prefmt(k), prefmt(v)) for k, v in _iteritems(data) + ) + @staticmethod def formatlist(data, name, fmt, sep): '''stringify iterable separated by sep''' @@ -287,8 +316,10 @@ prefmt = pycompat.bytestr return sep.join(fmt % prefmt(e) for e in data) + class plainformatter(baseformatter): '''the default text output scheme''' + def __init__(self, ui, out, topic, opts): baseformatter.__init__(self, ui, topic, opts, _plainconverter) if ui.debugflag: @@ -299,67 +330,88 @@ self._write = ui.write else: self._write = lambda s, **opts: out.write(s) + def startitem(self): pass + def data(self, **data): pass + def write(self, fields, deftext, *fielddata, **opts): self._write(deftext % fielddata, **opts) + def condwrite(self, cond, fields, deftext, *fielddata, **opts): '''do conditional write''' if cond: self._write(deftext % fielddata, **opts) + def plain(self, text, **opts): self._write(text, **opts) + def isplain(self): return True + def nested(self, field, tmpl=None, sep=''): # nested data will be directly written to ui return self + def end(self): pass + class debugformatter(baseformatter): def __init__(self, ui, out, topic, opts): baseformatter.__init__(self, ui, topic, opts, _nullconverter) self._out = out self._out.write("%s = [\n" % self._topic) + def _showitem(self): - self._out.write(' %s,\n' - % stringutil.pprint(self._item, indent=4, level=1)) + self._out.write( + ' %s,\n' % stringutil.pprint(self._item, indent=4, level=1) + ) + def end(self): baseformatter.end(self) self._out.write("]\n") + class pickleformatter(baseformatter): def __init__(self, ui, out, topic, opts): baseformatter.__init__(self, ui, topic, opts, _nullconverter) self._out = out self._data = [] + def _showitem(self): self._data.append(self._item) + def end(self): baseformatter.end(self) self._out.write(pickle.dumps(self._data)) + class cborformatter(baseformatter): '''serialize items as an indefinite-length CBOR array''' + def __init__(self, ui, out, topic, opts): baseformatter.__init__(self, ui, topic, opts, _nullconverter) self._out = out self._out.write(cborutil.BEGIN_INDEFINITE_ARRAY) + def _showitem(self): self._out.write(b''.join(cborutil.streamencode(self._item))) + def end(self): baseformatter.end(self) self._out.write(cborutil.BREAK) + class jsonformatter(baseformatter): def __init__(self, ui, out, topic, opts): baseformatter.__init__(self, ui, topic, opts, _nullconverter) self._out = out self._out.write("[") self._first = True + def _showitem(self): if self._first: self._first = False @@ -376,10 +428,12 @@ u = templatefilters.json(v, paranoid=False) self._out.write(' "%s": %s' % (k, u)) self._out.write("\n }") + def end(self): baseformatter.end(self) self._out.write("\n]\n") + class _templateconverter(object): '''convert non-primitive data types to be processed by templater''' @@ -389,37 +443,51 @@ def wrapnested(data, tmpl, sep): '''wrap nested data by templatable type''' return templateutil.mappinglist(data, tmpl=tmpl, sep=sep) + @staticmethod def formatdate(date, fmt): '''return date tuple''' return templateutil.date(date) + @staticmethod def formatdict(data, key, value, fmt, sep): '''build object that can be evaluated as either plain string or dict''' data = util.sortdict(_iteritems(data)) + def f(): yield _plainconverter.formatdict(data, key, value, fmt, sep) - return templateutil.hybriddict(data, key=key, value=value, fmt=fmt, - gen=f) + + return templateutil.hybriddict( + data, key=key, value=value, fmt=fmt, gen=f + ) + @staticmethod def formatlist(data, name, fmt, sep): '''build object that can be evaluated as either plain string or list''' data = list(data) + def f(): yield _plainconverter.formatlist(data, name, fmt, sep) + return templateutil.hybridlist(data, name=name, fmt=fmt, gen=f) + class templateformatter(baseformatter): def __init__(self, ui, out, topic, opts): baseformatter.__init__(self, ui, topic, opts, _templateconverter) self._out = out spec = lookuptemplate(ui, topic, opts.get('template', '')) self._tref = spec.ref - self._t = loadtemplater(ui, spec, defaults=templatekw.keywords, - resources=templateresources(ui), - cache=templatekw.defaulttempl) - self._parts = templatepartsmap(spec, self._t, - ['docheader', 'docfooter', 'separator']) + self._t = loadtemplater( + ui, + spec, + defaults=templatekw.keywords, + resources=templateresources(ui), + cache=templatekw.defaulttempl, + ) + self._parts = templatepartsmap( + spec, self._t, ['docheader', 'docfooter', 'separator'] + ) self._counter = itertools.count() self._renderitem('docheader', {}) @@ -448,12 +516,14 @@ baseformatter.end(self) self._renderitem('docfooter', {}) + @attr.s(frozen=True) class templatespec(object): ref = attr.ib() tmpl = attr.ib() mapfile = attr.ib() + def lookuptemplate(ui, topic, tmpl): """Find the template matching the given -T/--template spec 'tmpl' @@ -479,8 +549,9 @@ # perhaps a stock style? if not os.path.split(tmpl)[0]: - mapname = (templater.templatepath('map-cmdline.' + tmpl) - or templater.templatepath(tmpl)) + mapname = templater.templatepath( + 'map-cmdline.' + tmpl + ) or templater.templatepath(tmpl) if mapname and os.path.isfile(mapname): return templatespec(topic, None, mapname) @@ -504,6 +575,7 @@ # constant string? return templatespec('', tmpl, None) + def templatepartsmap(spec, t, partnames): """Create a mapping of {part: ref}""" partsmap = {spec.ref: spec.ref} # initial ref must exist in t @@ -516,32 +588,40 @@ partsmap[part] = ref return partsmap + def loadtemplater(ui, spec, defaults=None, resources=None, cache=None): """Create a templater from either a literal template or loading from a map file""" assert not (spec.tmpl and spec.mapfile) if spec.mapfile: frommapfile = templater.templater.frommapfile - return frommapfile(spec.mapfile, defaults=defaults, resources=resources, - cache=cache) - return maketemplater(ui, spec.tmpl, defaults=defaults, resources=resources, - cache=cache) + return frommapfile( + spec.mapfile, defaults=defaults, resources=resources, cache=cache + ) + return maketemplater( + ui, spec.tmpl, defaults=defaults, resources=resources, cache=cache + ) + def maketemplater(ui, tmpl, defaults=None, resources=None, cache=None): """Create a templater from a string template 'tmpl'""" aliases = ui.configitems('templatealias') - t = templater.templater(defaults=defaults, resources=resources, - cache=cache, aliases=aliases) - t.cache.update((k, templater.unquotestring(v)) - for k, v in ui.configitems('templates')) + t = templater.templater( + defaults=defaults, resources=resources, cache=cache, aliases=aliases + ) + t.cache.update( + (k, templater.unquotestring(v)) for k, v in ui.configitems('templates') + ) if tmpl: t.cache[''] = tmpl return t + # marker to denote a resource to be loaded on demand based on mapping values # (e.g. (ctx, path) -> fctx) _placeholder = object() + class templateresources(templater.resourcemapper): """Resource mapper designed for the default templatekw and function""" @@ -553,8 +633,9 @@ } def availablekeys(self, mapping): - return {k for k in self.knownkeys() - if self._getsome(mapping, k) is not None} + return { + k for k in self.knownkeys() if self._getsome(mapping, k) is not None + } def knownkeys(self): return {'cache', 'ctx', 'fctx', 'repo', 'revcache', 'ui'} @@ -611,7 +692,7 @@ try: return repo[node] except error.RepoLookupError: - return None # maybe hidden/non-existent node + return None # maybe hidden/non-existent node def _loadfctx(self, mapping): ctx = self._getsome(mapping, 'ctx') @@ -621,13 +702,14 @@ try: return ctx[path] except error.LookupError: - return None # maybe removed file? + return None # maybe removed file? _loadermap = { 'ctx': _loadctx, 'fctx': _loadfctx, } + def formatter(ui, out, topic, opts): template = opts.get("template", "") if template == "cbor": @@ -648,6 +730,7 @@ return jsonformatter(ui, out, topic, opts) return plainformatter(ui, out, topic, opts) + @contextlib.contextmanager def openformatter(ui, filename, topic, opts): """Create a formatter that writes outputs to the specified file @@ -658,10 +741,12 @@ with formatter(ui, out, topic, opts) as fm: yield fm + @contextlib.contextmanager def _neverending(fm): yield fm + def maybereopen(fm, filename): """Create a formatter backed by file if filename specified, else return the given formatter