dahlia / iterfzf

Pythonic interface to fzf, a CLI fuzzy finder
https://pypi.python.org/pypi/iterfzf
GNU General Public License v3.0
164 stars 19 forks source link

How do I iterate over Dictionary values? #8

Closed Aeres-u99 closed 4 years ago

Aeres-u99 commented 4 years ago

So basically I have a dictionary

d = {
"1":"foo",
"2":"bar",
"3":"spam",
"4":"Eggs"
}

I would like to be able to search through foo,bar etc and return the corresponding id. Even If I could get the key and value both of selection, that'd be fine as well. I have tried following:

iterfzf(d,multi=True) which basically allows me to select the keys as dictionaries are iterable over keys. then iterfzf(d.values(),multi=True) shows nothing else other than 0 0 and exits without any errors iterfzf(d.items(),multi=True) shows some weird behaviour and error as follows:

(tgD) > cat __init__.py                                                                                                finder
───────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: __init__.py
───────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ from iterfzf import iterfzf
   2   │ 
   3   │ 
   4   │ d = {
   5   │     "1":'Message',
   6   │     "2":'Message',
   7   │     "3":'Message',
   8   │     "4":'keke',
   9   │      }
  10   │ a = iterfzf(d.items(),multi=True)
  11   │ print(a)
───────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
(tgD) > python3 __init__.py                                                                                            finder
Traceback (most recent call last):
                                    File "__init__.py", line 10, in <module>
                                                                                a = iterfzf(d.items(),multi=True)
                                                                                                                   File "/home/akuma/SoopaProject/TelegramProjects/tgD/tgD/lib/python3.6/site-packages/iterfzf/__init__.py", line 81, in iterfzf
                                                                                                                      line = line.encode(encoding)
                    AttributeError: 'tuple' object has no attribute 'encode'
                                                                            Failed to read /dev/tty

It shows the error in exact disoriented manner.

I would like to know the correct way to achieve the desired result as well as once specified would go ahead and make the pr with appropriate inclusion in documentation. Thank you for this awesome module and for your generous time. using d.iteritems gives following Error:

(tgD) > python3 __init__.py                                                                                            finder
Traceback (most recent call last):
                                    File "__init__.py", line 10, in <module>
                                                                                a = iterfzf(d.iteritems(),multi=True)
                                                                                                                     AttributeError: 'dict' object has no attribute 'iteritems'
                                                 %                                                                            (tgD) >                                                                                                           finder RC=1

EDIT: Added the iteritems error

dahlia commented 4 years ago

Currently iterfzf() only accepts Unicode strings (i.e., str) or byte strings (i.e., bytes), not arbitrary Python objects like tuples. That's why iterfzf(d.items()) raises an error, as dict.items() returns an iterable of pairs, not strings.

As iterfzf() takes only strings and there is no way to give each item some “hidden keys” besides displayed values (and I believe it's same to fzf), you need to give iterfzf() string representations of key–value pairs. Here's an example:

from iterfzf import iterfzf

def fzf_dict(d, multi):
    options = ('{0}\t{1}'.format(k, v) for k, v in d.items())
    for kv in iterfzf(options, multi=multi):
        yield kv[:kv.index('\t')]

def main():
    d = {
        '1': 'foo',
        '2': 'bar',
        '3': 'spam',
        '4': 'egg',
    }
    print(iterfzf(d.values()))
    keys = fzf_dict(d, multi=True)
    for key in keys:
        print(repr(key), '=>', repr(d[key]))

if __name__ == '__main__':
    main()

The above code assumes keys must have no tabs, hence '\t' as a separator.

iterfzf(d.values(),multi=True) shows nothing else other than 0 0 and exits without any errors

I believe iterfzf(d.values()) must show dictionary values, but I am not sure why you've experienced that. I guess it's because you did it in an IPython session, which directly deals with TTY?

Aeres-u99 commented 4 years ago

Ahh thank you very much for explanation. Should we add this into the documentation as well? It will come in very handy. Are we planning to change it in anyways in near future?

dahlia commented 4 years ago

I believe the limitation (that it takes only strings) should be fixed in the upstream fzf project. In the docs I already wrote it only accepts Unicode strings or byte strings. Or do you mean other part of the docs?

Aeres-u99 commented 4 years ago

I mean the workaround for these, like the one you just suggested to me. imho this is fantastic I will definitely want to see more of the development :D

dahlia commented 4 years ago

Okay, I added the example code into the repository's examples/ directory:

https://github.com/dahlia/iterfzf/blob/2d13fdf04f2e85581feb721ace4064111e444cdf/examples/kv.py#L1-L34