Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork32k
gh-90117: handle dict and mapping views in pprint#30135
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
…d ._pprint_dict_items_view.
the-knights-who-say-ni commentedDec 16, 2021
Hello, and thanks for your contribution! I'm a bot set up to make sure that the project can legally accept this contribution by verifying everyone involved has signed thePSF contributor agreement (CLA). CLA MissingOur records indicate the following people have not signed the CLA: For legal reasons we need all the people listed to sign the CLA before we can look at your contribution. Please followthe steps outlined in the CPython devguide to rectify this issue. If you have recently signed the CLA, please wait at least one business day You cancheck yourself to see if the CLA has been received. Thanks again for the contribution, we look forward to reviewing it! |
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Thank you for the review, Alex! |
Pleasure :) You can add a News entry to your PR usinghttps://blurb-it.herokuapp.com |
Uh oh!
There was an error while loading.Please reload this page.
…int_dict_items_view.
Thank you for reviewing, Éric! |
This PR is stale because it has been open for 30 days with no activity. |
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
There is also thecollections.abc.KeysView
,ValuesView
andItemsView
classes, all of which should be able to reuse the logic used here for the various dict views. For the sake of consistency, I think it would be worthwhile to include them as well.
The sake of consistency is not a sufficient reason to do things. The question should be: what is the feature added by handling dict views ABCs in pprint? Do people pretty-print these ABCs? Would registering them automatically handle instance of concrete subclasses of the ABCs? In that case, should that replace the code added in this PR? |
Data point of 1, but I've personally run into this exact issue before, both with normal dict views as well as custom mapping views derived from the
Registering the The only caveat is that because the mapping views share identical @@ -233,8 +233,11 @@ def _pprint_ordered_dict(self, object, stream, indent, allowance, context, level- def _pprint_dict_view(self, object, stream, indent, allowance, context, level, items=False):- key = _safe_tuple if items else _safe_key+ def _pprint_dict_view(self, object, stream, indent, allowance, context, level):+ if isinstance(object, (self._dict_items_view, _collections.abc.ItemsView)):+ key = _safe_tuple+ else:+ key = _safe_key@@ -255,11 +258,10 @@ def _pprint_dict_view(self, object, stream, indent, allowance, context, level, i- def _pprint_dict_items_view(self, object, stream, indent, allowance, context, level):- self._pprint_dict_view(object, stream, indent, allowance, context, level, items=True)- _dict_items_view = type({}.items())- _dispatch[_dict_items_view.__repr__] = _pprint_dict_items_view+ _dispatch[_dict_items_view.__repr__] = _pprint_dict_view++ _dispatch[_collections.abc.MappingView.__repr__] = _pprint_dict_view |
…nto pprint_dict_view
…nto pprint_dict_view
I believe this PR is now ready for review. Any feedback is most welcome! It tries to keep the changes self-contained and use the same code style as the rest of the module, matching the code for pretty printing of dicts as closely as possible. It also adds and adapts many tests, to ensure full coverage of the changes. I now believe supporting ABC mapping views is worth it: it adds little code and broadens the kinds of mapping for which we can pretty print views. Some choices, like calling Code and output for pretty printing many kinds of viewsimportpprintfromcollectionsimportOrderedDict,defaultdict,Counter,ChainMapfromcollections.abcimportMapping,MappingView,ItemsView,KeysView,ValuesViewABC_MAPPING_VIEWS=MappingView,ItemsView,KeysView,ValuesViewDICT_CLASSES=OrderedDict,Counter,ChainMapdefmain():# Simple dictionary with string keys and valuessimple_dict= {"apple":"fruit","carrot":"vegetable","pear":"fruit"}# Dictionary with various types of keys and valuesmixed_dict= {42:"answer", (2,3): [1,2,3],'key': {'nested':'dict'}}# Long dictionary with integer keys and string valueslong_dict= {i:f"number_{i}"foriinrange(20)}# Long recursive dictionaryrecursive_dict=long_dict.copy()recursive_dict[20]=recursive_dict# Dictionary containing viewsviews_dict= {i:cls({i:i})fori,clsinenumerate(ABC_MAPPING_VIEWS)}start=len(ABC_MAPPING_VIEWS)views_dict.update({i+start:cls({i:i}).items()fori,clsinenumerate(DICT_CLASSES)})int_default_dict=defaultdict(int)int_default_dict[0]=0views_dict.update({7:int_default_dict.items()})# Ordered dictionary to maintain insertion orderordered_dict=OrderedDict([(f"key_{i}",i)foriinrange(20)])# Default dictionary with a default factory of listdefault_dict=defaultdict(list)default_dict['fruits'].append('apple')default_dict['fruits'].append('banana')default_dict['vegetables'].append('carrot')# Counter dictionary to count occurrencescounter_dict=Counter('abracadabra')# ChainMap to search multiple dictionarieschain_map=ChainMap(simple_dict,mixed_dict,long_dict)# Nested dictionary viewsnested_dict= {'level1':simple_dict,'level2': {'level2_dict':mixed_dict}}# Printing different dictionaries with pprintprint("Simple Dict Keys:")pprint.pprint(simple_dict.keys())print("\nMixed Dict Items:")pprint.pprint(mixed_dict.items())print("\nLong Dict Values:")pprint.pprint(long_dict.values(),width=50)print("\nOrdered Dict Items:")pprint.pprint(ordered_dict.items())print("\nDefault Dict Items:")pprint.pprint(default_dict.items())print("\nCounter Dict Items:")pprint.pprint(counter_dict.items())print("\nChainMap Items:")pprint.pprint(chain_map.items())print("\nNested Dict Views:")pprint.pprint(nested_dict.keys())pprint.pprint(nested_dict.items())pprint.pprint(nested_dict.items(),depth=2)print("\nRecursive Dict Views:")pprint.pprint(recursive_dict.items())print("\nABC Mapping Views (should pretty print a repr of the mapping):")pprint.pprint(MappingView(recursive_dict))pprint.pprint(ItemsView(nested_dict))pprint.pprint(KeysView(chain_map))pprint.pprint(ValuesView(ordered_dict))print("\nDict With Views:")pprint.pprint(views_dict.items())classes()defclasses():classMappingview_Custom_Repr(MappingView):def__repr__(self):return'*'*len(MappingView.__repr__(self))print("\nCustom __repr__ in Subclass:")pprint.pprint(Mappingview_Custom_Repr({1:1}))classMyMapping(Mapping):def__init__(self,keys=None):self._keys= {}ifkeysisNoneelsedict.fromkeys(keys)def__getitem__(self,item):returnself._keys[item]def__len__(self):returnlen(self._keys)def__iter__(self):returniter(self._keys)def__repr__(self):returnf"{self.__class__.__name__}([{', '.join(map(repr,self._keys.keys()))}])"print("\nCustom __repr__ in _mapping:")my_mapping=MyMapping(["test",1])pprint.pprint(MappingView(my_mapping))pprint.pprint(my_mapping.items())if__name__=="__main__":main() Output:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I confirm that the changes perform as indicated. This all works well.
I think the only oddity is the recursive printing, but I don't think that should be a block. Instead, if someone has a great idea for how to better handle recursively printing blocks (or, for example, asking if this is useful enough to warrant more attention), then they can do that later.
python-cla-botbot commentedApr 18, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
[Hello from PyCon's CPython sprint!]
I looked it over and did some manual testing and is working correctly. Good work!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
agreed (pairing) - this is in a good state and is an improvement over existing pprint behavior.
c7f8e70
intopython:mainUh oh!
There was an error while loading.Please reload this page.
A small thing: github unhelpfully defaults merge commit message to the concatenation of all commits in the branch. One needs to delete it before merging. The browser extension Refined Github helps with this. |
Uh oh!
There was an error while loading.Please reload this page.
This PR adds two methods to PrettyPrinter: one to handle
dict_keys
anddict_values
(sorted with_safe_key
), another to handledict_items
(sorted using_safe_tuple
).Design and implementation open for discussion, thanks in advance.
https://bugs.python.org/issue45959