-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Added 3 formatters:
fmt_prefixed_unit
, fmt_time_delta
, `fmt_aut…
…o_float`.
- Loading branch information
Showing
14 changed files
with
583 additions
and
48 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
VERSION=1.7.3 | ||
VERSION=1.7.4 | ||
PYPI_USERNAME=__token__ | ||
PYPI_PASSWORD= #api token |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# ----------------------------------------------------------------------------- | ||
# pytermor [ANSI formatted terminal output toolset] | ||
# (C) 2022 A. Shavykin <0.delameter@gmail.com> | ||
# ----------------------------------------------------------------------------- | ||
from .filter import * | ||
from .fmtd import * | ||
|
||
from .auto_float import * | ||
from .prefixed_unit import * | ||
from .time_delta import * | ||
|
||
__all__ = [ | ||
'apply_filters', | ||
'StringFilter', | ||
'ReplaceCSI', | ||
'ReplaceSGR', | ||
'ReplaceNonAsciiBytes', | ||
|
||
'ljust_fmtd', | ||
'rjust_fmtd', | ||
'center_fmtd', | ||
|
||
'fmt_prefixed_unit', | ||
'fmt_time_delta', | ||
'fmt_auto_float', | ||
'PrefixedUnitFmtPreset', | ||
'TimeDeltaFmtPreset', | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# ----------------------------------------------------------------------------- | ||
# pytermor [ANSI formatted terminal output toolset] | ||
# (C) 2022 A. Shavykin <0.delameter@gmail.com> | ||
# ----------------------------------------------------------------------------- | ||
from math import trunc | ||
|
||
|
||
def fmt_auto_float(value: float, max_len: int, output_int: bool) -> str: | ||
""" | ||
Dynamically adjust decimal digits amount to fill up output string | ||
with significant digits as much as possible. | ||
Examples: | ||
- auto_float(1234.56, 4, False) -> 1235 | ||
- auto_float(123.56, 4, False) -> 124 | ||
- auto_float(12.56, 4, False) -> 12.6 | ||
- auto_float(1.56, 4, False) -> 1.56 | ||
- auto_float(1234.56, 4, True) -> 1235 | ||
- auto_float(12.56, 4, True) -> 13 | ||
:param value: value to format | ||
:param max_len: maximum output string length (total) | ||
:param output_int: omit decimal point and everything to the right of it | ||
:return: formatted value | ||
""" | ||
if not output_int: | ||
max_decimals_len = 2 | ||
integer_len = len(str(trunc(value))) | ||
decimals_and_point_len = min(max_decimals_len + 1, max_len - integer_len) | ||
|
||
decimals_len = 0 | ||
if decimals_and_point_len >= 2: # dot without decimals makes no sense | ||
decimals_len = decimals_and_point_len - 1 | ||
dot_str = f'.{decimals_len!s}' | ||
else: | ||
dot_str = '.0' | ||
|
||
return f'{value:{max_len}{dot_str}f}' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# ----------------------------------------------------------------------------- | ||
# pytermor [ANSI formatted terminal output toolset] | ||
# (C) 2022 A. Shavykin <0.delameter@gmail.com> | ||
# ----------------------------------------------------------------------------- | ||
|
||
def get_terminal_width(): | ||
try: | ||
import shutil as _shutil | ||
return _shutil.get_terminal_size().columns - 2 | ||
except ImportError: | ||
return 80 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
# ----------------------------------------------------------------------------- | ||
# pytermor [ANSI formatted terminal output toolset] | ||
# (C) 2022 A. Shavykin <0.delameter@gmail.com> | ||
# ----------------------------------------------------------------------------- | ||
from . import ReplaceSGR | ||
|
||
|
||
def ljust_fmtd(s: str, width: int, fillchar: str = ' ') -> str: | ||
""" | ||
Correctly justifies input that can include SGR sequences. Apart from | ||
that is very similar to regular str.ljust(). | ||
:param s: string to extend | ||
:param width: target string length | ||
:param fillchar: append this char to target | ||
:return: **s** padded to the left side with *fillchars* so that now it's | ||
length corresponds to *width* | ||
""" | ||
sanitized = ReplaceSGR().apply(s) | ||
return s + fillchar * max(0, width - len(sanitized)) | ||
|
||
|
||
def rjust_fmtd(s: str, width: int, fillchar: str = ' ') -> str: | ||
""" | ||
SGR-aware implementation of str.rjust(). @see: ljust_fmtd | ||
""" | ||
sanitized = ReplaceSGR().apply(s) | ||
return fillchar * max(0, width - len(sanitized)) + s | ||
|
||
|
||
def center_fmtd(s: str, width: int, fillchar: str = ' ') -> str: | ||
""" | ||
SGR-aware implementation of str.rjust(). | ||
.. seealso:: ljust_fmtd | ||
.. note:: blabla | ||
.. todo:: blabla | ||
""" | ||
sanitized = ReplaceSGR().apply(s) | ||
fill_len = max(0, width - len(sanitized)) | ||
if fill_len == 0: | ||
return s | ||
right_fill_len = fill_len // 2 | ||
left_fill_len = fill_len - right_fill_len | ||
return (fillchar * left_fill_len) + s + (fillchar * right_fill_len) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
# ----------------------------------------------------------------------------- | ||
# pytermor [ANSI formatted terminal output toolset] | ||
# (C) 2022 A. Shavykin <0.delameter@gmail.com> | ||
# ----------------------------------------------------------------------------- | ||
from __future__ import annotations | ||
|
||
from dataclasses import dataclass | ||
from typing import List | ||
|
||
from . import fmt_auto_float | ||
|
||
|
||
@dataclass | ||
class PrefixedUnitFmtPreset: | ||
""" | ||
Default settings are suitable for formatting sizes in bytes ( | ||
*mcoef* =1024, prefixes are k, M, G, T etc.) | ||
*max_value_len* cannot effectively be less than 3, at least | ||
as long as *prefix_coef* =1024, because there is no way for | ||
method to insert into output more digits than it can shift | ||
back using multiplier (/divider) coefficient and prefixed units. | ||
""" | ||
max_value_len: int = 5 | ||
expand_to_max: bool = False | ||
mcoef: float = 1024.0 | ||
unit: str|None = 'b' | ||
unit_separator: str|None = ' ' | ||
prefixes: List[str] = None | ||
|
||
|
||
FMT_PRESET_DEFAULT_KEY = 8 | ||
FMT_PRESETS = {FMT_PRESET_DEFAULT_KEY: PrefixedUnitFmtPreset()} | ||
|
||
FMT_PREFIXES_DEFAULT = ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z'] | ||
|
||
|
||
def fmt_prefixed_unit(value: int, preset: PrefixedUnitFmtPreset = None) -> str: | ||
""" | ||
Format *value* using *preset* settings. The main idea of this method | ||
is to fit into specified string length as much significant digits as it's | ||
theoretically possible, using increasing coefficients and unit prefixes to | ||
indicate power. | ||
:param value: input value | ||
:param preset: formatter settings | ||
:return: formatted value | ||
""" | ||
if preset is None: | ||
preset = FMT_PRESETS[FMT_PRESET_DEFAULT_KEY] | ||
value = max(0, value) | ||
|
||
def iterator(_value: float) -> str: | ||
prefixes = preset.prefixes if preset.prefixes else FMT_PREFIXES_DEFAULT | ||
for unit_idx, unit_prefix in enumerate(prefixes): | ||
unit = preset.unit if preset.unit else "" | ||
unit_separator = preset.unit_separator if preset.unit_separator else "" | ||
unit_full = f'{unit_prefix}{unit}' | ||
|
||
if _value >= preset.mcoef: | ||
_value /= preset.mcoef | ||
continue | ||
|
||
num_str = fmt_auto_float(_value, preset.max_value_len, (unit_idx == 0)) | ||
return f'{num_str}{unit_separator}{unit_full}' | ||
|
||
# no more prefixes left | ||
return f'{_value!r:{preset.max_value_len}.{preset.max_value_len}}{preset.unit_separator or ""}' + \ | ||
'?' * max([len(p) for p in prefixes]) + \ | ||
(preset.unit or "") | ||
|
||
result = iterator(value) | ||
if not preset.expand_to_max: | ||
result = result.strip() | ||
return result |
Oops, something went wrong.