'.format(
+ html.escape(c)
+ ),
+ file=self._file,
+ )
self._unopened.clear()
if isinstance(msg, Data):
_, ext = os.path.splitext(msg.name)
filename = self._write_hash(msg.data, ext)
- text = '
{name}'.format(href=urllib.parse.quote(filename), name=html.escape(msg.name))
+ text = '
{name}'.format(
+ href=urllib.parse.quote(filename), name=html.escape(msg.name)
+ )
else:
text = html.escape(msg)
- print('
{}
'.format(level.value, text), file=self._file, flush=True)
+ print(
+ '
{}
'.format(level.value, text),
+ file=self._file,
+ flush=True,
+ )
def close(self) -> bool:
- if hasattr(self, '_file') and not self._file.closed:
+ if hasattr(self, "_file") and not self._file.closed:
self._file.write(HTMLFOOT)
self._file.close()
return True
else:
return False
- def __enter__(self) -> 'HtmlLog':
+ def __enter__(self) -> "HtmlLog":
return self
- def __exit__(self, t: typing.Optional[typing.Type[BaseException]], value: typing.Optional[BaseException], traceback: typing.Optional[types.TracebackType]) -> None:
+ def __exit__(
+ self,
+ t: typing.Optional[typing.Type[BaseException]],
+ value: typing.Optional[BaseException],
+ traceback: typing.Optional[types.TracebackType],
+ ) -> None:
self.close()
def __del__(self) -> None:
if self.close():
- warnings.warn('unclosed object {!r}'.format(self), ResourceWarning)
+ warnings.warn("unclosed object {!r}".format(self), ResourceWarning)
def _write_hash(self, data, ext):
filename = hashlib.sha1(data).hexdigest() + ext
try:
- with (self._path / filename).open('xb') as f:
+ with (self._path / filename).open("xb") as f:
f.write(data)
except FileExistsError:
pass
return filename
-HTMLHEAD = '''\
+HTMLHEAD = """\
@@ -99,13 +126,13 @@ def _write_hash(self, data, ext):
-'''
+"""
-HTMLFOOT = '''\
+HTMLFOOT = """\
-'''
+"""
-CSS = '''\
+CSS = """\
body { font-family: monospace; font-size: 12px; }
a, a:visited, a:hover { color: inherit; text-decoration: underline; }
@@ -192,9 +219,9 @@ def _write_hash(self, data, ext):
#theater.overview .plot_container3 { height: calc(100% - 20px); display: flex; align-items: center; justify-content: center; }
#theater.overview .plot { background: white; max-width: 100%; max-height: 100%; }
#theater.overview .label { position: absolute; width: 100%; left: 0px; right: 0px; bottom: 0px; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
-'''
+"""
-JS = '''\
+JS = """\
'use strict';
// LOW LEVEL UTILS
@@ -750,10 +777,12 @@ def _write_hash(self, data, ext):
apply_state(state);
state_control = 'enabled';
});
-'''
-
-FAVICON = 'data:image/png;base64,' \
- 'iVBORw0KGgoAAAANSUhEUgAAANIAAADSAgMAAABC93bRAAAACVBMVEUAAGcAAAD////NzL25' \
- 'AAAAAXRSTlMAQObYZgAAAFtJREFUaN7t2SEOACEMRcEa7ofh/ldBsJJAS1bO86Ob/MZY9ViN' \
- 'TD0oiqIo6qrOURRFUVRepQ4TRVEURdXVV6MoiqKoV2UJpCiKov7+p1AURVFUWZWiKIqiqI2a' \
- '8O8qJ0n+GP4AAAAASUVORK5CYII='
+"""
+
+FAVICON = (
+ "data:image/png;base64,"
+ "iVBORw0KGgoAAAANSUhEUgAAANIAAADSAgMAAABC93bRAAAACVBMVEUAAGcAAAD////NzL25"
+ "AAAAAXRSTlMAQObYZgAAAFtJREFUaN7t2SEOACEMRcEa7ofh/ldBsJJAS1bO86Ob/MZY9ViN"
+ "TD0oiqIo6qrOURRFUVRepQ4TRVEURdXVV6MoiqKoV2UJpCiKov7+p1AURVFUWZWiKIqiqI2a"
+ "8O8qJ0n+GP4AAAAASUVORK5CYII="
+)
diff --git a/treelog/_logging.py b/treelog/_logging.py
index 93f6d0f..4258506 100644
--- a/treelog/_logging.py
+++ b/treelog/_logging.py
@@ -5,12 +5,12 @@
class LoggingLog:
- '''Log to Python's built-in logging facility.'''
+ """Log to Python's built-in logging facility."""
# type: typing.ClassVar[typing.Tuple[int, int, int, int, int]]
_levels = logging.DEBUG, logging.INFO, 25, logging.WARNING, logging.ERROR
- def __init__(self, name: str = 'nutils') -> None:
+ def __init__(self, name: str = "nutils") -> None:
self._logger = logging.getLogger(name)
self.currentcontext = [] # type: typing.List[str]
@@ -24,5 +24,6 @@ def recontext(self, title: str) -> None:
self.currentcontext[-1] = title
def write(self, msg, level: Level, data: typing.Optional[bytes] = None) -> None:
- self._logger.log(self._levels[level.value], ' > '.join(
- (*self.currentcontext, str(msg))))
+ self._logger.log(
+ self._levels[level.value], " > ".join((*self.currentcontext, str(msg)))
+ )
diff --git a/treelog/_null.py b/treelog/_null.py
index 27f048e..249f87d 100644
--- a/treelog/_null.py
+++ b/treelog/_null.py
@@ -2,7 +2,6 @@
class NullLog:
-
def pushcontext(self, title: str) -> None:
pass
diff --git a/treelog/_path.py b/treelog/_path.py
index ee8398c..ac9da2c 100644
--- a/treelog/_path.py
+++ b/treelog/_path.py
@@ -17,13 +17,13 @@ def makedirs(*pathsegments):
def sequence(filename: str) -> typing.Generator[str, None, None]:
- '''Generate file names a.b, a-1.b, a-2.b, etc.'''
+ """Generate file names a.b, a-1.b, a-2.b, etc."""
yield filename
splitext = os.path.splitext(filename)
i = 1
while True:
- yield '-{}'.format(i).join(splitext)
+ yield "-{}".format(i).join(splitext)
i += 1
@@ -41,11 +41,10 @@ def non_existent(path, names, f):
# continue to the next name only if the path indeed exists.
if not isinstance(path, pathlib.Path) or not (path / name).exists():
raise
- raise Exception('names exhausted')
+ raise Exception("names exhausted")
class _FDDirPath:
-
def __init__(self, dir_fd: int) -> None:
self._opener = functools.partial(os.open, dir_fd=dir_fd)
self._close = functools.partial(os.close, dir_fd)
@@ -59,10 +58,13 @@ def __del__(self) -> None:
class _FDFilePath:
-
def __init__(self, directory, filename):
self._directory = directory
self._filename = filename
- def open(self, mode: str, *, encoding: typing.Optional[str] = None) -> typing.IO[typing.Any]:
- return open(self._filename, mode, encoding=encoding, opener=self._directory._opener)
+ def open(
+ self, mode: str, *, encoding: typing.Optional[str] = None
+ ) -> typing.IO[typing.Any]:
+ return open(
+ self._filename, mode, encoding=encoding, opener=self._directory._opener
+ )
diff --git a/treelog/_record.py b/treelog/_record.py
index 399ce21..07d9fd7 100644
--- a/treelog/_record.py
+++ b/treelog/_record.py
@@ -1,12 +1,10 @@
-import contextlib
-import tempfile
import typing
from .proto import Level, Log
class RecordLog:
- '''Record log messages.
+ """Record log messages.
The recorded messages can be replayed to the logs that are currently active
by :meth:`replay`. Typical usage is caching expensive operations:
@@ -26,7 +24,7 @@ class RecordLog:
.. Note::
Exceptions raised while in a :meth:`Log.context` are not recorded.
- '''
+ """
def __init__(self, simplify: bool = True):
# Replayable log messages. Each entry is a tuple of `(cmd, *args)`, where
@@ -37,41 +35,50 @@ def __init__(self, simplify: bool = True):
self._fid = 0 # internal file counter
def pushcontext(self, title: str) -> None:
- if self._simplify and self._messages and self._messages[-1][0] == 'popcontext':
- self._messages[-1] = 'recontext', title
+ if self._simplify and self._messages and self._messages[-1][0] == "popcontext":
+ self._messages[-1] = "recontext", title
else:
- self._messages.append(('pushcontext', title))
+ self._messages.append(("pushcontext", title))
def recontext(self, title: str) -> None:
- if self._simplify and self._messages and self._messages[-1][0] in ('pushcontext', 'recontext'):
+ if (
+ self._simplify
+ and self._messages
+ and self._messages[-1][0] in ("pushcontext", "recontext")
+ ):
self._messages[-1] = self._messages[-1][0], title
else:
- self._messages.append(('recontext', title))
+ self._messages.append(("recontext", title))
def popcontext(self) -> None:
- if not self._simplify or not self._messages or self._messages[-1][0] not in ('pushcontext', 'recontext') or self._messages.pop()[0] == 'recontext':
- self._messages.append(('popcontext',))
+ if (
+ not self._simplify
+ or not self._messages
+ or self._messages[-1][0] not in ("pushcontext", "recontext")
+ or self._messages.pop()[0] == "recontext"
+ ):
+ self._messages.append(("popcontext",))
def write(self, msg, level: Level) -> None:
- self._messages.append(('write', msg, level))
+ self._messages.append(("write", msg, level))
def replay(self, log: typing.Optional[Log] = None) -> None:
- '''Replay this recorded log.
+ """Replay this recorded log.
All recorded messages and files will be written to the log that is either
- directly specified or currently active.'''
+ directly specified or currently active."""
if log is None:
from ._state import current as log
for cmd, *args in self._messages:
- if cmd == 'pushcontext':
- title, = args
+ if cmd == "pushcontext":
+ (title,) = args
log.pushcontext(title)
- elif cmd == 'recontext':
- title, = args
+ elif cmd == "recontext":
+ (title,) = args
log.recontext(title)
- elif cmd == 'popcontext':
+ elif cmd == "popcontext":
log.popcontext()
- elif cmd == 'write':
+ elif cmd == "write":
msg, level = args
log.write(msg, level)
diff --git a/treelog/_richoutput.py b/treelog/_richoutput.py
index a0fd774..71c6348 100644
--- a/treelog/_richoutput.py
+++ b/treelog/_richoutput.py
@@ -1,21 +1,22 @@
import sys
import typing
-from .proto import Level
+from .proto import Level, Data
class RichOutputLog:
- '''Output rich (colored,unicode) text to stream.'''
+ """Output rich (colored,unicode) text to stream."""
_cmap = (
- '\033[1;30m', # debug: bold gray
- '\033[1m', # info: bold
- '\033[1;34m', # user: bold blue
- '\033[1;35m', # warning: bold purple
- '\033[1;31m') # error: bold red
+ "\033[1;30m", # debug: bold gray
+ "\033[1m", # info: bold
+ "\033[1;34m", # user: bold blue
+ "\033[1;35m", # warning: bold purple
+ "\033[1;31m",
+ ) # error: bold red
def __init__(self, file=sys.stdout) -> None:
- self._current = '' # currently printed context
+ self._current = "" # currently printed context
self.file = file
set_ansi_console()
self.currentcontext = [] # type: typing.List[str]
@@ -33,33 +34,43 @@ def recontext(self, title: str) -> None:
self.contextchangedhook()
def contextchangedhook(self) -> None:
- _current = ''.join(item + ' > ' for item in self.currentcontext)
+ _current = "".join(item + " > " for item in self.currentcontext)
if _current == self._current:
return
n = first(c1 != c2 for c1, c2 in zip(_current, self._current))
items = []
if n == 0 and self._current:
- items.append('\r')
+ items.append("\r")
elif n < len(self._current):
- items.append('\033[{}D'.format(len(self._current)-n))
+ items.append("\033[{}D".format(len(self._current) - n))
if n < len(_current):
items.append(_current[n:])
if len(_current) < len(self._current):
- items.append('\033[K')
- self.file.write(''.join(items))
+ items.append("\033[K")
+ self.file.write("".join(items))
self.file.flush()
self._current = _current
def write(self, msg, level: Level) -> None:
- msg = str(msg)
- if self._current and '\n' in msg:
- msg = msg.replace('\n', '\033[0m\n' + ' > '.rjust(len(self._current)) + self._cmap[level.value])
+ if isinstance(msg, Data):
+ info = f" [{msg.info}]"
+ msg = msg.name
+ else:
+ info = ""
+ if self._current and "\n" in msg:
+ msg = msg.replace(
+ "\n",
+ "\033[0m\n" + " > ".rjust(len(self._current)) + self._cmap[level.value],
+ )
self.file.write(
- ''.join([self._cmap[level.value], msg, '\033[0m\n', self._current]))
+ "".join(
+ [self._cmap[level.value], msg, "\033[0m", info, "\n", self._current]
+ )
+ )
def first(items: typing.Iterable[bool]) -> int:
- 'return index of first truthy item, or len(items) of all items are falsy'
+ "return index of first truthy item, or len(items) of all items are falsy"
i = 0
for item in items:
if item:
@@ -71,10 +82,15 @@ def first(items: typing.Iterable[bool]) -> int:
def set_ansi_console() -> None:
if sys.platform == "win32":
import platform
- if platform.version() < '10.':
+
+ if platform.version() < "10.":
raise RuntimeError(
- 'ANSI console mode requires Windows 10 or higher, detected {}'.format(platform.version()))
+ "ANSI console mode requires Windows 10 or higher, detected {}".format(
+ platform.version()
+ )
+ )
import ctypes
+
# https://docs.microsoft.com/en-us/windows/console/getstdhandle
handle = ctypes.windll.kernel32.GetStdHandle(-11)
# https://docs.microsoft.com/en-us/windows/desktop/WinProg/windows-data-types#lpdword
diff --git a/treelog/_state.py b/treelog/_state.py
index 444d86a..82bcde5 100644
--- a/treelog/_state.py
+++ b/treelog/_state.py
@@ -16,7 +16,7 @@
@contextlib.contextmanager
def set(logger: Log) -> typing.Generator[Log, None, None]:
- '''Set logger as current.'''
+ """Set logger as current."""
global current
old = current
@@ -28,32 +28,35 @@ def set(logger: Log) -> typing.Generator[Log, None, None]:
def add(logger: Log) -> typing.ContextManager[Log]:
- '''Add logger to current.'''
+ """Add logger to current."""
return set(TeeLog(current, logger))
def disable() -> typing.ContextManager[Log]:
- '''Disable logger.'''
+ """Disable logger."""
return set(NullLog())
@contextlib.contextmanager
-def context(title: str, *initargs: typing.Any, **initkwargs: typing.Any) -> typing.Generator[typing.Optional[typing.Callable[..., None]], None, None]:
- '''Enterable context.
+def context(
+ title: str, *initargs: typing.Any, **initkwargs: typing.Any
+) -> typing.Generator[typing.Optional[typing.Callable[..., None]], None, None]:
+ """Enterable context.
Returns an enterable object which upon enter creates a context with a given
title, to be automatically closed upon exit. In case additional arguments are
given the title is used as a format string, and a callable is returned that
- allows for recontextualization from within the current with-block.'''
+ allows for recontextualization from within the current with-block."""
log = current
if initargs or initkwargs:
format = title.format
- # type: typing.Optional[typing.Callable[..., None]]
- reformat = lambda *args, **kwargs: log.recontext(
- format(*args, **kwargs))
+
+ def reformat(*args, **kwargs):
+ log.recontext(format(*args, **kwargs))
+
title = title.format(*initargs, **initkwargs)
else:
reformat = None
@@ -64,20 +67,22 @@ def context(title: str, *initargs: typing.Any, **initkwargs: typing.Any) -> typi
log.popcontext()
-T = typing.TypeVar('T')
+T = typing.TypeVar("T")
+
def withcontext(f: typing.Callable[..., T]) -> typing.Callable[..., T]:
- '''Decorator; executes the wrapped function in its own logging context.'''
+ """Decorator; executes the wrapped function in its own logging context."""
@functools.wraps(f)
def wrapped(*args: typing.Any, **kwargs: typing.Any) -> T:
with context(f.__name__):
return f(*args, **kwargs)
+
return wrapped
-def write(level: Level, *args: typing.Any, sep: str = ' ') -> None:
- '''Write message to log.
+def write(level: Level, *args: typing.Any, sep: str = " ") -> None:
+ """Write message to log.
Args
----
@@ -85,28 +90,27 @@ def write(level: Level, *args: typing.Any, sep: str = ' ') -> None:
Values to be printed to the log.
sep : :class:`str`
String inserted between values, default a space.
- '''
+ """
current.write(sep.join(map(str, args)), level)
@contextlib.contextmanager
def file(level: Level, name: str, mode: str, type: typing.Optional[str] = None):
- '''Open file in logger-controlled directory.
+ """Open file in logger-controlled directory.
Args
----
filename : :class:`str`
mode : :class:`str`
Should be either ``'w'`` (text) or ``'wb'`` (binary data).
- '''
+ """
- if mode == 'wb':
+ if mode == "wb":
binary = True
- elif mode == 'w':
+ elif mode == "w":
binary = False
else:
- raise ValueError(f'invalid mode {mode!r}')
- logger = current
+ raise ValueError(f"invalid mode {mode!r}")
with tempfile.TemporaryFile() as f, context(name):
yield f if binary else io.TextIOWrapper(f, write_through=True)
f.seek(0)
@@ -119,10 +123,10 @@ def data(level: Level, name: str, data: bytes, type: typing.Optional[str] = None
def partial(attr):
- if attr.endswith('file'):
+ if attr.endswith("file"):
f = file
level = attr[:-4]
- elif attr.endswith('data'):
+ elif attr.endswith("data"):
f = data
level = attr[:-4]
else:
diff --git a/treelog/_stdout.py b/treelog/_stdout.py
index fcc846c..b10ae06 100644
--- a/treelog/_stdout.py
+++ b/treelog/_stdout.py
@@ -4,23 +4,23 @@
class StdoutLog:
- '''Output plain text to stream.'''
+ """Output plain text to stream."""
def __init__(self, file=sys.stdout):
self.file = file
self.currentcontext = [] # type: typing.List[str]
def pushcontext(self, title: str) -> None:
- self.currentcontext.append(title + ' > ')
+ self.currentcontext.append(title + " > ")
def popcontext(self) -> None:
self.currentcontext.pop()
def recontext(self, title: str) -> None:
- self.currentcontext[-1] = title + ' > '
+ self.currentcontext[-1] = title + " > "
def write(self, msg, level: proto.Level) -> None:
if self.currentcontext:
- prefix = ''.join(self.currentcontext)
- msg = prefix + str(msg).replace('\n', '\n' + ' > '.rjust(len(prefix)))
+ prefix = "".join(self.currentcontext)
+ msg = prefix + str(msg).replace("\n", "\n" + " > ".rjust(len(prefix)))
print(msg, file=self.file)
diff --git a/treelog/_tee.py b/treelog/_tee.py
index 8080a3d..b237ce3 100644
--- a/treelog/_tee.py
+++ b/treelog/_tee.py
@@ -1,12 +1,8 @@
-import contextlib
-import os
-import tempfile
-
from .proto import Level, Log
class TeeLog:
- '''Forward messages to two underlying loggers.'''
+ """Forward messages to two underlying loggers."""
def __init__(self, baselog1: Log, baselog2: Log) -> None:
self._baselog1 = baselog1
diff --git a/treelog/iter.py b/treelog/iter.py
index d867bab..654830d 100644
--- a/treelog/iter.py
+++ b/treelog/iter.py
@@ -1,33 +1,36 @@
import itertools
-import functools
import warnings
import inspect
import typing
import types
-from . import proto, _state
+from . import _state
-T = typing.TypeVar('T')
-T0 = typing.TypeVar('T0')
-T1 = typing.TypeVar('T1')
-T2 = typing.TypeVar('T2')
-T3 = typing.TypeVar('T3')
-T4 = typing.TypeVar('T4')
-T5 = typing.TypeVar('T5')
-T6 = typing.TypeVar('T6')
-T7 = typing.TypeVar('T7')
-T8 = typing.TypeVar('T8')
-T9 = typing.TypeVar('T9')
+T = typing.TypeVar("T")
+T0 = typing.TypeVar("T0")
+T1 = typing.TypeVar("T1")
+T2 = typing.TypeVar("T2")
+T3 = typing.TypeVar("T3")
+T4 = typing.TypeVar("T4")
+T5 = typing.TypeVar("T5")
+T6 = typing.TypeVar("T6")
+T7 = typing.TypeVar("T7")
+T8 = typing.TypeVar("T8")
+T9 = typing.TypeVar("T9")
class wrap(typing.Generic[T]):
- '''Wrap iterable in consecutive title contexts.
+ """Wrap iterable in consecutive title contexts.
The wrapped iterable is identical to the original, except that prior to every
next item a new log context is opened taken from the ``titles`` iterable. The
wrapped object should be entered before use in order to ensure that this
- context is properly closed in case the iterator is prematurely abandoned.'''
+ context is properly closed in case the iterator is prematurely abandoned."""
- def __init__(self, titles: typing.Union[typing.Iterable[str], typing.Generator[str, T, None]], iterable: typing.Iterable[T]) -> None:
+ def __init__(
+ self,
+ titles: typing.Union[typing.Iterable[str], typing.Generator[str, T, None]],
+ iterable: typing.Iterable[T],
+ ) -> None:
self._titles = iter(titles)
self._iterable = iter(iterable)
self._log = None # type: typing.Optional[proto.Log]
@@ -35,7 +38,7 @@ def __init__(self, titles: typing.Union[typing.Iterable[str], typing.Generator[s
def __enter__(self) -> typing.Iterator[T]:
if self._log is not None:
- raise Exception('iter.wrap is not reentrant')
+ raise Exception("iter.wrap is not reentrant")
self._log = _state.current
self._log.pushcontext(next(self._titles))
return iter(self)
@@ -44,19 +47,29 @@ def __iter__(self) -> typing.Generator[T, None, None]:
if self._log is not None:
cansend = inspect.isgenerator(self._titles)
for value in self._iterable:
- self._log.recontext(typing.cast(typing.Generator[str, T, None], self._titles).send(
- value) if cansend else next(self._titles))
+ self._log.recontext(
+ typing.cast(typing.Generator[str, T, None], self._titles).send(
+ value
+ )
+ if cansend
+ else next(self._titles)
+ )
yield value
else:
with self:
self._warn = True
yield from self
- def __exit__(self, exctype: typing.Optional[typing.Type[BaseException]], excvalue: typing.Optional[BaseException], tb: typing.Optional[types.TracebackType]) -> None:
+ def __exit__(
+ self,
+ exctype: typing.Optional[typing.Type[BaseException]],
+ excvalue: typing.Optional[BaseException],
+ tb: typing.Optional[types.TracebackType],
+ ) -> None:
if self._log is None:
- raise Exception('iter.wrap has not yet been entered')
+ raise Exception("iter.wrap has not yet been entered")
if self._warn and exctype is GeneratorExit:
- warnings.warn('unclosed iter.wrap', ResourceWarning)
+ warnings.warn("unclosed iter.wrap", ResourceWarning)
self._log.popcontext()
self._log = None
@@ -66,48 +79,109 @@ def plain(title: str, __arg0: typing.Iterable[T0]) -> wrap[T0]: ...
@typing.overload
-def plain(title: str, __arg0: typing.Iterable[T0],
- __arg1: typing.Iterable[T1]) -> wrap[typing.Tuple[T0, T1]]: ...
+def plain(
+ title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1]
+) -> wrap[typing.Tuple[T0, T1]]: ...
@typing.overload
-def plain(title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1],
- __arg2: typing.Iterable[T2]) -> wrap[typing.Tuple[T0, T1, T2]]: ...
+def plain(
+ title: str,
+ __arg0: typing.Iterable[T0],
+ __arg1: typing.Iterable[T1],
+ __arg2: typing.Iterable[T2],
+) -> wrap[typing.Tuple[T0, T1, T2]]: ...
@typing.overload
-def plain(title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1],
- __arg2: typing.Iterable[T2], __arg3: typing.Iterable[T3]) -> wrap[typing.Tuple[T0, T1, T2, T3]]: ...
+def plain(
+ title: str,
+ __arg0: typing.Iterable[T0],
+ __arg1: typing.Iterable[T1],
+ __arg2: typing.Iterable[T2],
+ __arg3: typing.Iterable[T3],
+) -> wrap[typing.Tuple[T0, T1, T2, T3]]: ...
@typing.overload
-def plain(title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1], __arg2: typing.Iterable[T2],
- __arg3: typing.Iterable[T3], __arg4: typing.Iterable[T4]) -> wrap[typing.Tuple[T0, T1, T2, T3, T4]]: ...
+def plain(
+ title: str,
+ __arg0: typing.Iterable[T0],
+ __arg1: typing.Iterable[T1],
+ __arg2: typing.Iterable[T2],
+ __arg3: typing.Iterable[T3],
+ __arg4: typing.Iterable[T4],
+) -> wrap[typing.Tuple[T0, T1, T2, T3, T4]]: ...
@typing.overload
-def plain(title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1], __arg2: typing.Iterable[T2], __arg3: typing.Iterable[T3],
- __arg4: typing.Iterable[T4], __arg5: typing.Iterable[T5]) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5]]: ...
+def plain(
+ title: str,
+ __arg0: typing.Iterable[T0],
+ __arg1: typing.Iterable[T1],
+ __arg2: typing.Iterable[T2],
+ __arg3: typing.Iterable[T3],
+ __arg4: typing.Iterable[T4],
+ __arg5: typing.Iterable[T5],
+) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5]]: ...
@typing.overload
-def plain(title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1], __arg2: typing.Iterable[T2], __arg3: typing.Iterable[T3],
- __arg4: typing.Iterable[T4], __arg5: typing.Iterable[T5], __arg6: typing.Iterable[T6]) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5, T6]]: ...
+def plain(
+ title: str,
+ __arg0: typing.Iterable[T0],
+ __arg1: typing.Iterable[T1],
+ __arg2: typing.Iterable[T2],
+ __arg3: typing.Iterable[T3],
+ __arg4: typing.Iterable[T4],
+ __arg5: typing.Iterable[T5],
+ __arg6: typing.Iterable[T6],
+) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5, T6]]: ...
@typing.overload
-def plain(title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1], __arg2: typing.Iterable[T2], __arg3: typing.Iterable[T3], __arg4: typing.Iterable[T4],
- __arg5: typing.Iterable[T5], __arg6: typing.Iterable[T6], __arg7: typing.Iterable[T7]) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5, T6, T7]]: ...
+def plain(
+ title: str,
+ __arg0: typing.Iterable[T0],
+ __arg1: typing.Iterable[T1],
+ __arg2: typing.Iterable[T2],
+ __arg3: typing.Iterable[T3],
+ __arg4: typing.Iterable[T4],
+ __arg5: typing.Iterable[T5],
+ __arg6: typing.Iterable[T6],
+ __arg7: typing.Iterable[T7],
+) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5, T6, T7]]: ...
@typing.overload
-def plain(title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1], __arg2: typing.Iterable[T2], __arg3: typing.Iterable[T3], __arg4: typing.Iterable[T4],
- __arg5: typing.Iterable[T5], __arg6: typing.Iterable[T6], __arg7: typing.Iterable[T7], __arg8: typing.Iterable[T8]) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5, T6, T7, T8]]: ...
+def plain(
+ title: str,
+ __arg0: typing.Iterable[T0],
+ __arg1: typing.Iterable[T1],
+ __arg2: typing.Iterable[T2],
+ __arg3: typing.Iterable[T3],
+ __arg4: typing.Iterable[T4],
+ __arg5: typing.Iterable[T5],
+ __arg6: typing.Iterable[T6],
+ __arg7: typing.Iterable[T7],
+ __arg8: typing.Iterable[T8],
+) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5, T6, T7, T8]]: ...
@typing.overload
-def plain(title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1], __arg2: typing.Iterable[T2], __arg3: typing.Iterable[T3], __arg4: typing.Iterable[T4], __arg5: typing.Iterable[T5],
- __arg6: typing.Iterable[T6], __arg7: typing.Iterable[T7], __arg8: typing.Iterable[T8], __arg9: typing.Iterable[T9]) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9]]: ...
+def plain(
+ title: str,
+ __arg0: typing.Iterable[T0],
+ __arg1: typing.Iterable[T1],
+ __arg2: typing.Iterable[T2],
+ __arg3: typing.Iterable[T3],
+ __arg4: typing.Iterable[T4],
+ __arg5: typing.Iterable[T5],
+ __arg6: typing.Iterable[T6],
+ __arg7: typing.Iterable[T7],
+ __arg8: typing.Iterable[T8],
+ __arg9: typing.Iterable[T9],
+) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9]]: ...
@typing.overload
@@ -115,154 +189,324 @@ def plain(title: str, *args: typing.Any) -> wrap[typing.Any]: ...
def plain(title: str, *args: typing.Any) -> wrap[typing.Any]:
- '''Wrap arguments in simple enumerated contexts.
+ """Wrap arguments in simple enumerated contexts.
Example: my context 1, my context 2, etc.
- '''
+ """
- titles = map((_escape(title) + ' {}').format, itertools.count())
+ titles = map((_escape(title) + " {}").format, itertools.count())
return wrap(titles, zip(*args) if len(args) > 1 else args[0])
@typing.overload
-def fraction(title: str, __arg0: typing.Iterable[T0], *,
- length: typing.Optional[int] = ...) -> wrap[T0]: ...
+def fraction(
+ title: str, __arg0: typing.Iterable[T0], *, length: typing.Optional[int] = ...
+) -> wrap[T0]: ...
@typing.overload
-def fraction(title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1],
- *, length: typing.Optional[int] = ...) -> wrap[typing.Tuple[T0, T1]]: ...
+def fraction(
+ title: str,
+ __arg0: typing.Iterable[T0],
+ __arg1: typing.Iterable[T1],
+ *,
+ length: typing.Optional[int] = ...,
+) -> wrap[typing.Tuple[T0, T1]]: ...
@typing.overload
-def fraction(title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1],
- __arg2: typing.Iterable[T2], *, length: typing.Optional[int] = ...) -> wrap[typing.Tuple[T0, T1, T2]]: ...
+def fraction(
+ title: str,
+ __arg0: typing.Iterable[T0],
+ __arg1: typing.Iterable[T1],
+ __arg2: typing.Iterable[T2],
+ *,
+ length: typing.Optional[int] = ...,
+) -> wrap[typing.Tuple[T0, T1, T2]]: ...
+
+
+@typing.overload
+def fraction(
+ title: str,
+ __arg0: typing.Iterable[T0],
+ __arg1: typing.Iterable[T1],
+ __arg2: typing.Iterable[T2],
+ __arg3: typing.Iterable[T3],
+ *,
+ length: typing.Optional[int] = ...,
+) -> wrap[typing.Tuple[T0, T1, T2, T3]]: ...
@typing.overload
-def fraction(title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1], __arg2: typing.Iterable[T2],
- __arg3: typing.Iterable[T3], *, length: typing.Optional[int] = ...) -> wrap[typing.Tuple[T0, T1, T2, T3]]: ...
+def fraction(
+ title: str,
+ __arg0: typing.Iterable[T0],
+ __arg1: typing.Iterable[T1],
+ __arg2: typing.Iterable[T2],
+ __arg3: typing.Iterable[T3],
+ __arg4: typing.Iterable[T4],
+ *,
+ length: typing.Optional[int] = ...,
+) -> wrap[typing.Tuple[T0, T1, T2, T3, T4]]: ...
@typing.overload
-def fraction(title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1], __arg2: typing.Iterable[T2], __arg3: typing.Iterable[T3],
- __arg4: typing.Iterable[T4], *, length: typing.Optional[int] = ...) -> wrap[typing.Tuple[T0, T1, T2, T3, T4]]: ...
+def fraction(
+ title: str,
+ __arg0: typing.Iterable[T0],
+ __arg1: typing.Iterable[T1],
+ __arg2: typing.Iterable[T2],
+ __arg3: typing.Iterable[T3],
+ __arg4: typing.Iterable[T4],
+ __arg5: typing.Iterable[T5],
+ *,
+ length: typing.Optional[int] = ...,
+) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5]]: ...
@typing.overload
-def fraction(title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1], __arg2: typing.Iterable[T2], __arg3: typing.Iterable[T3],
- __arg4: typing.Iterable[T4], __arg5: typing.Iterable[T5], *, length: typing.Optional[int] = ...) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5]]: ...
+def fraction(
+ title: str,
+ __arg0: typing.Iterable[T0],
+ __arg1: typing.Iterable[T1],
+ __arg2: typing.Iterable[T2],
+ __arg3: typing.Iterable[T3],
+ __arg4: typing.Iterable[T4],
+ __arg5: typing.Iterable[T5],
+ __arg6: typing.Iterable[T6],
+ *,
+ length: typing.Optional[int] = ...,
+) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5, T6]]: ...
@typing.overload
-def fraction(title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1], __arg2: typing.Iterable[T2], __arg3: typing.Iterable[T3], __arg4: typing.Iterable[T4],
- __arg5: typing.Iterable[T5], __arg6: typing.Iterable[T6], *, length: typing.Optional[int] = ...) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5, T6]]: ...
+def fraction(
+ title: str,
+ __arg0: typing.Iterable[T0],
+ __arg1: typing.Iterable[T1],
+ __arg2: typing.Iterable[T2],
+ __arg3: typing.Iterable[T3],
+ __arg4: typing.Iterable[T4],
+ __arg5: typing.Iterable[T5],
+ __arg6: typing.Iterable[T6],
+ __arg7: typing.Iterable[T7],
+ *,
+ length: typing.Optional[int] = ...,
+) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5, T6, T7]]: ...
@typing.overload
-def fraction(title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1], __arg2: typing.Iterable[T2], __arg3: typing.Iterable[T3], __arg4: typing.Iterable[T4],
- __arg5: typing.Iterable[T5], __arg6: typing.Iterable[T6], __arg7: typing.Iterable[T7], *, length: typing.Optional[int] = ...) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5, T6, T7]]: ...
-
-
-@typing.overload
-def fraction(title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1], __arg2: typing.Iterable[T2], __arg3: typing.Iterable[T3], __arg4: typing.Iterable[T4], __arg5: typing.Iterable[T5],
- __arg6: typing.Iterable[T6], __arg7: typing.Iterable[T7], __arg8: typing.Iterable[T8], *, length: typing.Optional[int] = ...) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5, T6, T7, T8]]: ...
-
-
-@typing.overload
-def fraction(title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1], __arg2: typing.Iterable[T2], __arg3: typing.Iterable[T3], __arg4: typing.Iterable[T4], __arg5: typing.Iterable[T5],
- __arg6: typing.Iterable[T6], __arg7: typing.Iterable[T7], __arg8: typing.Iterable[T8], __arg9: typing.Iterable[T9], *, length: typing.Optional[int] = ...) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9]]: ...
-
-
-@typing.overload
-def fraction(title: str, *args: typing.Any,
- length: typing.Optional[int] = ...) -> wrap[typing.Any]: ...
-
-
-def fraction(title: str, *args: typing.Any, length: typing.Optional[int] = None) -> wrap[typing.Any]:
- '''Wrap arguments in enumerated contexts with length.
+def fraction(
+ title: str,
+ __arg0: typing.Iterable[T0],
+ __arg1: typing.Iterable[T1],
+ __arg2: typing.Iterable[T2],
+ __arg3: typing.Iterable[T3],
+ __arg4: typing.Iterable[T4],
+ __arg5: typing.Iterable[T5],
+ __arg6: typing.Iterable[T6],
+ __arg7: typing.Iterable[T7],
+ __arg8: typing.Iterable[T8],
+ *,
+ length: typing.Optional[int] = ...,
+) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5, T6, T7, T8]]: ...
+
+
+@typing.overload
+def fraction(
+ title: str,
+ __arg0: typing.Iterable[T0],
+ __arg1: typing.Iterable[T1],
+ __arg2: typing.Iterable[T2],
+ __arg3: typing.Iterable[T3],
+ __arg4: typing.Iterable[T4],
+ __arg5: typing.Iterable[T5],
+ __arg6: typing.Iterable[T6],
+ __arg7: typing.Iterable[T7],
+ __arg8: typing.Iterable[T8],
+ __arg9: typing.Iterable[T9],
+ *,
+ length: typing.Optional[int] = ...,
+) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9]]: ...
+
+
+@typing.overload
+def fraction(
+ title: str, *args: typing.Any, length: typing.Optional[int] = ...
+) -> wrap[typing.Any]: ...
+
+
+def fraction(
+ title: str, *args: typing.Any, length: typing.Optional[int] = None
+) -> wrap[typing.Any]:
+ """Wrap arguments in enumerated contexts with length.
Example: my context 1/5, my context 2/5, etc.
- '''
+ """
if length is None:
length = min(len(arg) for arg in args)
- titles = map((_escape(title) + ' {}/' + str(length)).format,
- itertools.count())
+ titles = map((_escape(title) + " {}/" + str(length)).format, itertools.count())
return wrap(titles, zip(*args) if len(args) > 1 else args[0])
@typing.overload
-def percentage(title: str, __arg0: typing.Iterable[T0],
- *, length: typing.Optional[int] = ...) -> wrap[T0]: ...
+def percentage(
+ title: str, __arg0: typing.Iterable[T0], *, length: typing.Optional[int] = ...
+) -> wrap[T0]: ...
@typing.overload
-def percentage(title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1],
- *, length: typing.Optional[int] = ...) -> wrap[typing.Tuple[T0, T1]]: ...
+def percentage(
+ title: str,
+ __arg0: typing.Iterable[T0],
+ __arg1: typing.Iterable[T1],
+ *,
+ length: typing.Optional[int] = ...,
+) -> wrap[typing.Tuple[T0, T1]]: ...
@typing.overload
-def percentage(title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1],
- __arg2: typing.Iterable[T2], *, length: typing.Optional[int] = ...) -> wrap[typing.Tuple[T0, T1, T2]]: ...
+def percentage(
+ title: str,
+ __arg0: typing.Iterable[T0],
+ __arg1: typing.Iterable[T1],
+ __arg2: typing.Iterable[T2],
+ *,
+ length: typing.Optional[int] = ...,
+) -> wrap[typing.Tuple[T0, T1, T2]]: ...
+
+
+@typing.overload
+def percentage(
+ title: str,
+ __arg0: typing.Iterable[T0],
+ __arg1: typing.Iterable[T1],
+ __arg2: typing.Iterable[T2],
+ __arg3: typing.Iterable[T3],
+ *,
+ length: typing.Optional[int] = ...,
+) -> wrap[typing.Tuple[T0, T1, T2, T3]]: ...
@typing.overload
-def percentage(title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1], __arg2: typing.Iterable[T2],
- __arg3: typing.Iterable[T3], *, length: typing.Optional[int] = ...) -> wrap[typing.Tuple[T0, T1, T2, T3]]: ...
+def percentage(
+ title: str,
+ __arg0: typing.Iterable[T0],
+ __arg1: typing.Iterable[T1],
+ __arg2: typing.Iterable[T2],
+ __arg3: typing.Iterable[T3],
+ __arg4: typing.Iterable[T4],
+ *,
+ length: typing.Optional[int] = ...,
+) -> wrap[typing.Tuple[T0, T1, T2, T3, T4]]: ...
@typing.overload
-def percentage(title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1], __arg2: typing.Iterable[T2], __arg3: typing.Iterable[T3],
- __arg4: typing.Iterable[T4], *, length: typing.Optional[int] = ...) -> wrap[typing.Tuple[T0, T1, T2, T3, T4]]: ...
+def percentage(
+ title: str,
+ __arg0: typing.Iterable[T0],
+ __arg1: typing.Iterable[T1],
+ __arg2: typing.Iterable[T2],
+ __arg3: typing.Iterable[T3],
+ __arg4: typing.Iterable[T4],
+ __arg5: typing.Iterable[T5],
+ *,
+ length: typing.Optional[int] = ...,
+) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5]]: ...
@typing.overload
-def percentage(title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1], __arg2: typing.Iterable[T2], __arg3: typing.Iterable[T3],
- __arg4: typing.Iterable[T4], __arg5: typing.Iterable[T5], *, length: typing.Optional[int] = ...) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5]]: ...
+def percentage(
+ title: str,
+ __arg0: typing.Iterable[T0],
+ __arg1: typing.Iterable[T1],
+ __arg2: typing.Iterable[T2],
+ __arg3: typing.Iterable[T3],
+ __arg4: typing.Iterable[T4],
+ __arg5: typing.Iterable[T5],
+ __arg6: typing.Iterable[T6],
+ *,
+ length: typing.Optional[int] = ...,
+) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5, T6]]: ...
@typing.overload
-def percentage(title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1], __arg2: typing.Iterable[T2], __arg3: typing.Iterable[T3], __arg4: typing.Iterable[T4],
- __arg5: typing.Iterable[T5], __arg6: typing.Iterable[T6], *, length: typing.Optional[int] = ...) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5, T6]]: ...
+def percentage(
+ title: str,
+ __arg0: typing.Iterable[T0],
+ __arg1: typing.Iterable[T1],
+ __arg2: typing.Iterable[T2],
+ __arg3: typing.Iterable[T3],
+ __arg4: typing.Iterable[T4],
+ __arg5: typing.Iterable[T5],
+ __arg6: typing.Iterable[T6],
+ __arg7: typing.Iterable[T7],
+ *,
+ length: typing.Optional[int] = ...,
+) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5, T6, T7]]: ...
@typing.overload
-def percentage(title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1], __arg2: typing.Iterable[T2], __arg3: typing.Iterable[T3], __arg4: typing.Iterable[T4],
- __arg5: typing.Iterable[T5], __arg6: typing.Iterable[T6], __arg7: typing.Iterable[T7], *, length: typing.Optional[int] = ...) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5, T6, T7]]: ...
-
-
-@typing.overload
-def percentage(title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1], __arg2: typing.Iterable[T2], __arg3: typing.Iterable[T3], __arg4: typing.Iterable[T4], __arg5: typing.Iterable[T5],
- __arg6: typing.Iterable[T6], __arg7: typing.Iterable[T7], __arg8: typing.Iterable[T8], *, length: typing.Optional[int] = ...) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5, T6, T7, T8]]: ...
-
-
-@typing.overload
-def percentage(title: str, __arg0: typing.Iterable[T0], __arg1: typing.Iterable[T1], __arg2: typing.Iterable[T2], __arg3: typing.Iterable[T3], __arg4: typing.Iterable[T4], __arg5: typing.Iterable[T5],
- __arg6: typing.Iterable[T6], __arg7: typing.Iterable[T7], __arg8: typing.Iterable[T8], __arg9: typing.Iterable[T9], *, length: typing.Optional[int] = ...) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9]]: ...
-
-
-@typing.overload
-def percentage(title: str, *args: typing.Any,
- length: typing.Optional[int] = ...) -> wrap[typing.Any]: ...
-
-
-def percentage(title: str, *args: typing.Any, length: typing.Optional[int] = None) -> wrap[typing.Any]:
- '''Wrap arguments in contexts with percentage counter.
+def percentage(
+ title: str,
+ __arg0: typing.Iterable[T0],
+ __arg1: typing.Iterable[T1],
+ __arg2: typing.Iterable[T2],
+ __arg3: typing.Iterable[T3],
+ __arg4: typing.Iterable[T4],
+ __arg5: typing.Iterable[T5],
+ __arg6: typing.Iterable[T6],
+ __arg7: typing.Iterable[T7],
+ __arg8: typing.Iterable[T8],
+ *,
+ length: typing.Optional[int] = ...,
+) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5, T6, T7, T8]]: ...
+
+
+@typing.overload
+def percentage(
+ title: str,
+ __arg0: typing.Iterable[T0],
+ __arg1: typing.Iterable[T1],
+ __arg2: typing.Iterable[T2],
+ __arg3: typing.Iterable[T3],
+ __arg4: typing.Iterable[T4],
+ __arg5: typing.Iterable[T5],
+ __arg6: typing.Iterable[T6],
+ __arg7: typing.Iterable[T7],
+ __arg8: typing.Iterable[T8],
+ __arg9: typing.Iterable[T9],
+ *,
+ length: typing.Optional[int] = ...,
+) -> wrap[typing.Tuple[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9]]: ...
+
+
+@typing.overload
+def percentage(
+ title: str, *args: typing.Any, length: typing.Optional[int] = ...
+) -> wrap[typing.Any]: ...
+
+
+def percentage(
+ title: str, *args: typing.Any, length: typing.Optional[int] = None
+) -> wrap[typing.Any]:
+ """Wrap arguments in contexts with percentage counter.
Example: my context 5%, my context 10%, etc.
- '''
+ """
if length is None:
length = min(len(arg) for arg in args)
if length:
# type: typing.Iterable[str]
titles = map(
- (_escape(title) + ' {:.0f}%').format, itertools.count(step=100/length))
+ (_escape(title) + " {:.0f}%").format, itertools.count(step=100 / length)
+ )
else:
- titles = title + ' 100%',
+ titles = (title + " 100%",)
return wrap(titles, zip(*args) if len(args) > 1 else args[0])
def _escape(s: str) -> str:
- return s.replace('{', '{{').replace('}', '}}')
+ return s.replace("{", "{{").replace("}", "}}")
diff --git a/treelog/proto.py b/treelog/proto.py
index be066d5..1339c27 100644
--- a/treelog/proto.py
+++ b/treelog/proto.py
@@ -4,7 +4,6 @@
class Level(Enum):
-
debug = 0
info = 1
user = 2
@@ -18,15 +17,18 @@ class Data:
data: bytes
type: Optional[str] = None
- def __str__(self):
- info = f'{len(self.data)} bytes'
+ @property
+ def info(self):
+ info = f"{len(self.data)} bytes"
if self.type:
- info = f'{self.type}; {info}'
- return f'{self.name} [{info}]'
+ info = f"{self.type}; {info}"
+ return info
+ def __str__(self):
+ return f"{self.name} [{self.info}]"
-class Log(Protocol):
+class Log(Protocol):
def pushcontext(self, title: str) -> None: ...
def popcontext(self) -> None: ...
def recontext(self, title: str) -> None: ...