prettyprinter icon indicating copy to clipboard operation
prettyprinter copied to clipboard

Counter prettyprinter should sort entries by count

Open anntzer opened this issue 6 years ago • 1 comments

  • PrettyPrinter version: 0.17.0
  • Python version: 3.7
  • Operating System: linux

Description

PrettyPrinter does not sort Counter()s entries by count, unlike Counter.__str__ which explicitly does so.

What I Did

In [1]: prettyprinter.pformat(collections.Counter({"a": 1, "b": 200}))
Out[1]: "collections.Counter({'a': 1, 'b': 200})"

In [2]: str(collections.Counter({"a": 1, "b": 200}))                                                                
Out[2]: "Counter({'b': 200, 'a': 1})"

I think the sorted form is clearly more useful (well, at least, it matches the intent of whoever wrote the stdlib's Counter.__str__).

On Py3.6+ I think it's just a matter of

diff --git i/prettyprinter/pretty_stdlib.py w/prettyprinter/pretty_stdlib.py
index 273ee0e..9c66171 100644
--- i/prettyprinter/pretty_stdlib.py
+++ w/prettyprinter/pretty_stdlib.py
@@ -296,7 +296,7 @@ def pretty_ordereddict(d, ctx):
 
 @register_pretty(Counter)
 def pretty_counter(counter, ctx):
-    return pretty_call_alt(ctx, type(counter), args=(dict(counter), ))
+    return pretty_call_alt(ctx, type(counter), args=(dict(counter.most_common()), ))
 
 
 @register_pretty('enum.Enum')

(well the stdlib's version has additionally some handling when most_common() fails due to unorderable values, but you get the idea) but I'm not sure how to make this work on Py3.5.

anntzer avatar Mar 19 '19 17:03 anntzer

I think this sounds good. I believe we'll need to extract logic from pretty_dict to a utility function that takes an iterable of key-value pairs instead of a dict, called something like pretty_dict_from_pairs so that we can use that function both here and in the implementation of pretty_dict. This will ensure Python 3.5 can correctly render the output in the most common order. Then the actual pretty printer for Counter can be implemented as

build_fncall(
    ctx,
    type(counter),
    argdocs=(
        pretty_dict_from_pairs(ctx, counter.most_common()),
    ),
    hug_sole_arg=True
)

tommikaikkonen avatar Mar 26 '19 08:03 tommikaikkonen