gmr / flatdict

Python module for interacting with nested dicts as a single level dict with delimited keys.
https://flatdict.readthedocs.io
BSD 3-Clause "New" or "Revised" License
112 stars 32 forks source link

Mixed key types cannot be at same level due to no ordering support between 'int' and 'str' #35

Closed nugend closed 4 years ago

nugend commented 5 years ago

I have a dictionary that has a level with mixed numeric and string values (it is imported through TOML where this is not an issue). This is causing an exception to be thrown here:

https://github.com/gmr/flatdict/blob/8b056a11526ef7fd13061137194ea9ed2fe09805/flatdict.py#L292-L300

If a key function along the lines of the following were passed to the sorted function, I think the issue could be resolved:

lambda x:(float('inf'),x) if isinstance(x,str) else (x,'')

I'm not sure how to handle this for Python < 3.2

wsantos commented 5 years ago

@nugend can you provide one example ?

nugend commented 5 years ago

An example of my configuration files or a dictionary with an integer/float and a string in the key? Sorry, a bit confused.

wsantos commented 5 years ago

@nugend The dict you are using so I can reproduce the problem.

nugend commented 5 years ago

Sure, a minimal example of the issue:

>>> flatdict.FlatDict({'':None,'1':None})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File ".../lib/python3.7/site-packages/flatdict.py", line 134, in __repr__
    str(self))
  File ".../lib/python3.7/site-packages/flatdict.py", line 166, in __str__
    ['{!r}: {!r}'.format(k, self[k]) for k in self.keys()]))
  File ".../lib/python3.7/site-packages/flatdict.py", line 298, in keys
    ] for key in keys
TypeError: '<' not supported between instances of 'int' and 'str'

Turns out the sort key function needs to be a little different: lambda xs: [(float('inf'),x) if isinstance(x,str) else (x,'') for x in xs]

avladev commented 4 years ago

I think the whole sorted() behavior should be optional.

I can simulate such behavior by removing the sorted() call in FlatDict.keys, but I am not familiar with the code.

There are two cases I can think of which does not require any sorting:

May be as_ordered_dict() also have to be provided for converting back to a dict and as_dict() keep the standard dictionary for compatibility reasons.

Also if you consider such behavior keep in mind that set() order also is not guaranteed eg. {'z', 'a', 'z', 'a', 1, 0} -> {0, 1, 'z', 'a'}, they are used in some of the methods.

It's good library. Thanks!

wsantos commented 4 years ago

@avladev the sort only applies on FlatterDict for lists not dicts, so it's already optional if you change the Dict class like you describe check #33, I'll try to fix this problem as soon I find some time.