Skip to content

Commit

Permalink
implement 'format-separator' option (#2737)
Browse files Browse the repository at this point in the history
a global option, that servers as a workaround for shortcomings due to
lack of a proper format string parser
  • Loading branch information
mikf committed Jul 10, 2022
1 parent 117eeef commit 74865ad
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 6 deletions.
14 changes: 14 additions & 0 deletions docs/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions gallery_dl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
13 changes: 7 additions & 6 deletions gallery_dl/formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -284,7 +284,7 @@ def apply_slice(obj):


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)

Expand All @@ -295,7 +295,7 @@ def mlen(obj):


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)

Expand All @@ -305,7 +305,7 @@ def join(obj):


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)

Expand All @@ -315,7 +315,7 @@ def replace(obj):


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)

Expand All @@ -325,7 +325,7 @@ def dt(obj):


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)

Expand Down Expand Up @@ -363,6 +363,7 @@ def __getitem__(key):
_literal = Literal()

_CACHE = {}
_SEPARATOR = "/"
_GLOBALS = {
"_env": lambda: os.environ,
"_lit": lambda: _literal,
Expand Down
20 changes: 20 additions & 0 deletions test/test_formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,26 @@ def test_chain_special(self):
# 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"]

Expand Down

0 comments on commit 74865ad

Please sign in to comment.