From 42481aed59759e4b44ec51b4f85efeafa22b50fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20F=C3=A4hrmann?= Date: Mon, 21 Nov 2022 21:44:42 +0100 Subject: [PATCH] [formatter] implement 'S' format specifier (#3266) to Sort lists --- docs/formatting.md | 6 ++++++ gallery_dl/formatter.py | 15 +++++++++++++++ gallery_dl/version.py | 2 +- test/test_formatter.py | 18 ++++++++++++++++++ 4 files changed, 40 insertions(+), 1 deletion(-) diff --git a/docs/formatting.md b/docs/formatting.md index 53cba565..5420c69e 100644 --- a/docs/formatting.md +++ b/docs/formatting.md @@ -172,6 +172,12 @@ Format specifiers can be used for advanced formatting by using the options provi {foo:Ro/()/} F()() Bar + + S<order>/ + Sort a list. <order> can be either ascending or descending/reverse. (default: a) + {tags:Sd} + ['water', 'tree', 'sun'] + D<format>/ Parse a string value to a datetime object according to <format> diff --git a/gallery_dl/formatter.py b/gallery_dl/formatter.py index dd32b8a5..ca05fa5a 100644 --- a/gallery_dl/formatter.py +++ b/gallery_dl/formatter.py @@ -347,6 +347,20 @@ def _parse_offset(format_spec, default): return off +def _parse_sort(format_spec, default): + args, _, format_spec = format_spec.partition(_SEPARATOR) + fmt = _build_format_func(format_spec, default) + + if "d" in args or "r" in args: + def sort_desc(obj): + return fmt(sorted(obj, reverse=True)) + return sort_desc + else: + def sort_asc(obj): + return fmt(sorted(obj)) + return sort_asc + + def _default_format(format_spec, default): def wrap(obj): return format(obj, format_spec) @@ -395,4 +409,5 @@ _FORMAT_SPECIFIERS = { "J": _parse_join, "O": _parse_offset, "R": _parse_replace, + "S": _parse_sort, } diff --git a/gallery_dl/version.py b/gallery_dl/version.py index 31dbc63f..dfbac9d8 100644 --- a/gallery_dl/version.py +++ b/gallery_dl/version.py @@ -6,4 +6,4 @@ # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. -__version__ = "1.24.0" +__version__ = "1.24.1-dev" diff --git a/test/test_formatter.py b/test/test_formatter.py index b3353326..50e55a6c 100644 --- a/test/test_formatter.py +++ b/test/test_formatter.py @@ -219,6 +219,21 @@ class TestFormatter(unittest.TestCase): time.timezone = orig_timezone time.altzone = orig_altzone + def test_sort(self): + self._run_test("{l:S}" , "['a', 'b', 'c']") + self._run_test("{l:Sa}", "['a', 'b', 'c']") + self._run_test("{l:Sd}", "['c', 'b', 'a']") + self._run_test("{l:Sr}", "['c', 'b', 'a']") + + self._run_test( + "{a:S}", "[' ', 'E', 'L', 'L', 'O', 'd', 'h', 'l', 'o', 'r', 'w']") + self._run_test( + "{a:S-asc}", # starts with 'S', contains 'a' + "[' ', 'E', 'L', 'L', 'O', 'd', 'h', 'l', 'o', 'r', 'w']") + self._run_test( + "{a:Sort-reverse}", # starts with 'S', contains 'r' + "['w', 'r', 'o', 'l', 'h', 'd', 'O', 'L', 'L', 'E', ' ']") + def test_chain_special(self): # multiple replacements self._run_test("{a:Rh/C/RE/e/RL/l/}", "Cello wOrld") @@ -237,6 +252,9 @@ class TestFormatter(unittest.TestCase): # parse and format datetime self._run_test("{ds:D%Y-%m-%dT%H:%M:%S%z/%Y%m%d}", "20100101") + # sort and join + self._run_test("{a:S/J}", " ELLOdhlorw") + def test_separator(self): orig_separator = formatter._SEPARATOR try: