[formatter] implement 'S' format specifier (#3266)

to Sort lists
pull/3307/head
Mike Fährmann 2 years ago
parent 8a021e4ee4
commit 42481aed59
No known key found for this signature in database
GPG Key ID: 5680CA389D365A88

@ -172,6 +172,12 @@ Format specifiers can be used for advanced formatting by using the options provi
<td><code>{foo:Ro/()/}</code></td> <td><code>{foo:Ro/()/}</code></td>
<td><code>F()()&nbsp;Bar</code></td> <td><code>F()()&nbsp;Bar</code></td>
</tr> </tr>
<tr>
<td><code>S&lt;order&gt;/</code></td>
<td>Sort a list. <code>&lt;order&gt;</code> can be either <strong>a</strong>scending or <strong>d</strong>escending/<strong>r</strong>everse. (default: <strong>a</strong>)</td>
<td><code>{tags:Sd}</code></td>
<td><code>['water', 'tree', 'sun']</code></td>
</tr>
<tr> <tr>
<td><code>D&lt;format&gt;/</code></td> <td><code>D&lt;format&gt;/</code></td>
<td>Parse a string value to a <code>datetime</code> object according to <a href="https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes"><code>&lt;format&gt;</code></a></td> <td>Parse a string value to a <code>datetime</code> object according to <a href="https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes"><code>&lt;format&gt;</code></a></td>

@ -347,6 +347,20 @@ def _parse_offset(format_spec, default):
return off 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 _default_format(format_spec, default):
def wrap(obj): def wrap(obj):
return format(obj, format_spec) return format(obj, format_spec)
@ -395,4 +409,5 @@ _FORMAT_SPECIFIERS = {
"J": _parse_join, "J": _parse_join,
"O": _parse_offset, "O": _parse_offset,
"R": _parse_replace, "R": _parse_replace,
"S": _parse_sort,
} }

@ -6,4 +6,4 @@
# it under the terms of the GNU General Public License version 2 as # it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation. # published by the Free Software Foundation.
__version__ = "1.24.0" __version__ = "1.24.1-dev"

@ -219,6 +219,21 @@ class TestFormatter(unittest.TestCase):
time.timezone = orig_timezone time.timezone = orig_timezone
time.altzone = orig_altzone 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): def test_chain_special(self):
# multiple replacements # multiple replacements
self._run_test("{a:Rh/C/RE/e/RL/l/}", "Cello wOrld") self._run_test("{a:Rh/C/RE/e/RL/l/}", "Cello wOrld")
@ -237,6 +252,9 @@ class TestFormatter(unittest.TestCase):
# parse and format datetime # parse and format datetime
self._run_test("{ds:D%Y-%m-%dT%H:%M:%S%z/%Y%m%d}", "20100101") 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): def test_separator(self):
orig_separator = formatter._SEPARATOR orig_separator = formatter._SEPARATOR
try: try:

Loading…
Cancel
Save