implement 'format-separator' option (#2737)

a global option, that servers as a workaround for shortcomings due to
lack of a proper format string parser
This commit is contained in:
Mike Fährmann 2022-07-10 13:30:45 +02:00
parent 117eeefda0
commit 74865adae5
No known key found for this signature in database
GPG Key ID: 5680CA389D365A88
4 changed files with 47 additions and 6 deletions

View File

@ -3710,6 +3710,20 @@ Description
this cache.
format-separator
----------------
Type
``string``
Default
``"/"``
Description
Character(s) used as argument separator in format string
`format specifiers <formatting.md#format-specifiers>`__.
For example, setting this option to ``"#"`` would allow a replacement
operation to be ``Rold#new#`` instead of the default ``Rold/new/``
signals-ignore
--------------
Type

View File

@ -177,6 +177,12 @@ def main():
extractor.modules = modules
extractor._module_iter = iter(modules)
# format string separator
separator = config.get((), "format-separator")
if separator:
from . import formatter
formatter._SEPARATOR = separator
# loglevels
output.configure_logging(args.loglevel)
if args.loglevel >= logging.ERROR:

View File

@ -264,7 +264,7 @@ def _build_format_func(format_spec, default):
def _parse_optional(format_spec, default):
before, after, format_spec = format_spec.split("/", 2)
before, after, format_spec = format_spec.split(_SEPARATOR, 2)
before = before[1:]
fmt = _build_format_func(format_spec, default)
@ -284,7 +284,7 @@ def _parse_slice(format_spec, default):
def _parse_maxlen(format_spec, default):
maxlen, replacement, format_spec = format_spec.split("/", 2)
maxlen, replacement, format_spec = format_spec.split(_SEPARATOR, 2)
maxlen = text.parse_int(maxlen[1:])
fmt = _build_format_func(format_spec, default)
@ -295,7 +295,7 @@ def _parse_maxlen(format_spec, default):
def _parse_join(format_spec, default):
separator, _, format_spec = format_spec.partition("/")
separator, _, format_spec = format_spec.partition(_SEPARATOR)
separator = separator[1:]
fmt = _build_format_func(format_spec, default)
@ -305,7 +305,7 @@ def _parse_join(format_spec, default):
def _parse_replace(format_spec, default):
old, new, format_spec = format_spec.split("/", 2)
old, new, format_spec = format_spec.split(_SEPARATOR, 2)
old = old[1:]
fmt = _build_format_func(format_spec, default)
@ -315,7 +315,7 @@ def _parse_replace(format_spec, default):
def _parse_datetime(format_spec, default):
dt_format, _, format_spec = format_spec.partition("/")
dt_format, _, format_spec = format_spec.partition(_SEPARATOR)
dt_format = dt_format[1:]
fmt = _build_format_func(format_spec, default)
@ -325,7 +325,7 @@ def _parse_datetime(format_spec, default):
def _parse_offset(format_spec, default):
offset, _, format_spec = format_spec.partition("/")
offset, _, format_spec = format_spec.partition(_SEPARATOR)
offset = offset[1:]
fmt = _build_format_func(format_spec, default)
@ -363,6 +363,7 @@ class Literal():
_literal = Literal()
_CACHE = {}
_SEPARATOR = "/"
_GLOBALS = {
"_env": lambda: os.environ,
"_lit": lambda: _literal,

View File

@ -236,6 +236,26 @@ class TestFormatter(unittest.TestCase):
# parse and format datetime
self._run_test("{ds:D%Y-%m-%dT%H:%M:%S%z/%Y%m%d}", "20100101")
def test_separator(self):
orig_separator = formatter._SEPARATOR
try:
formatter._SEPARATOR = "|"
self._run_test("{a:Rh|C|RE|e|RL|l|}", "Cello wOrld")
self._run_test("{d[b]!s:R1|Q|R2|A|R0|Y|}", "Y")
formatter._SEPARATOR = "##"
self._run_test("{l:J-##Rb##E##}", "a-E-c")
self._run_test("{l:J-##[1:-1]}", "-b-")
formatter._SEPARATOR = "\0"
self._run_test("{d[a]:?<\0>\0L1\0too long\0}", "<too long>")
self._run_test("{d[c]:?<\0>\0L5\0too long\0}", "")
formatter._SEPARATOR = "?"
self._run_test("{ds:D%Y-%m-%dT%H:%M:%S%z?%Y%m%d}", "20100101")
finally:
formatter._SEPARATOR = orig_separator
def test_globals_env(self):
os.environ["FORMATTER_TEST"] = value = self.kwdict["a"]