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
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. |
* Teach pprint about dict views with PrettyPrinter._pprint_dict_view and ._pprint_dict_items_view.* Use _private names for _dict_*_view attributes of PrettyPrinter.* Use explicit 'items' keyword when calling _pprint_dict_view from _pprint_dict_items_view.* 📜🤖 Added by blurb_it.* Improve tests* Add tests for collections.abc.[Keys|Items|Mapping|Values]View support in pprint.* Add support for collections.abc.[Keys|Items|Mapping|Values]View in pprint.* Split _pprint_dict_view into _pprint_abc_view, so pretty-printing normal dict views and ABC views is handled in two simple methods.* Simplify redundant code.* Add collections.abc views to some existing pprint tests.* Test that views from collection.UserDict are correctly formatted by pprint.* Handle recursive dict and ABC views.* Test that subclasses of ABC views work in pprint.* Test dict views coming from collections.Counter.* Test ABC views coming from collections.ChainMap.* Test odict views coming from collections.OrderedDict.* Rename _pprint_abc_view to _pprint_mapping_abc_view.* Add pprint test for mapping ABC views where ._mapping has a custom __repr__ and fix ChainMap test.* When a mapping ABC view has a ._mapping that defines a custom __repr__, dispatch pretty-printing it by that __repr__.* Add tests for ABC mapping views subclasses that don't replace __repr__, also handling those that delete ._mapping on instances.* Simplify the pretty printing of ABC mapping views.* Add a test for depth handling when pretty printing dict views.* Fix checking whether the view type is a subclass of an items view, add a test.* Move construction of the views __repr__ set out of _safe_repr.---------Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>Co-authored-by: Éric <merwok@netwok.org>Co-authored-by: Oleg Iarygin <oleg@arhadthedev.net>Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>Co-authored-by: Gregory P. Smith <greg@krypto.org>
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