1

So my my problem is that I'm running a program once it has finished base functions a pop up box appears asking the user if they would like to save file, if 'yes' then a save dialog box appears. Because the data I'm saving is a dict value I'm receiving an Error from tkinter. I have attempted to use the ".csv" extension as a save point as i read somewhere that dict's can be saved to them, but i'm either going about this wrong way or there is an issue within my code.

Updated Code and explanation why below

Original snippet of code:

def flag_detection():

total_count = Counter(traffic_light)
total_count.keys()
for key, value in total_count.items():

    EWT = tkinter.messagebox.askquestion('File Level', 'Would you like to save')

    file_opt = options = {}
    options['filetypes'] = [('all files', '.*'), ('text files', '.csv')]
    options['initialfile'] = 'myfile.csv'

    if EWT == 'yes':
        savename = asksaveasfile(file_opt, defaultextension=".csv")
        savename.write(key, ':', value)

Error message:

    Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\Lewis Collins\AppData\Local\Programs\Python\Python35-32\lib\tkinter\__init__.py", line 1550, in __call__
    return self.func(*args)
  File "C:/Users/Lewis Collins/PycharmProjects/program_06.01.17/Home.py", line 108, in run_language_model
    main.flag_detection()
  File "C:\Users\Lewis Collins\PycharmProjects\program_06.01.17\main_code\main.py", line 179, in flag_detection
    savename = asksaveasfile(file_opt, defaultextension=".csv")
  File "C:\Users\Lewis Collins\AppData\Local\Programs\Python\Python35-32\lib\tkinter\filedialog.py", line 423, in asksaveasfile
    return open(filename, mode)
TypeError: open() argument 2 must be str, not dict

Because of Tkinter throwing back that it can not save a dict to file i tried the below solution of converting the dict to a str which has also caused problems

Code Snippet of Function attempt to convert to str for tkinter:

def flag_detection():


total_count = Counter(traffic_light)
total_count.keys()
for key, value in str(total_count.items()):
    EWT = tkinter.messagebox.askquestion('File Level', 'Would you like to save')
    file_opt = options = {}
    options['filetypes'] = [('all files', '.*'), ('text files', '.csv')]
    options['initialfile'] = 'myfile.csv'

    if EWT == 'yes':
        savename = asksaveasfile(file_opt, defaultextension=".csv")
        savename.write(key, ':', value)

So I've updated my code to try and use the str(total_count.items()): to convert to dict as i didn't quite understand the json and pickle libraries after reading them they seemed to complicated for what i needed which is a simple output to a file for a user to be able to go and view.

I am now receiving this Error:

    Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\Lewis Collins\AppData\Local\Programs\Python\Python35-32\lib\tkinter\__init__.py", line 1550, in __call__
    return self.func(*args)
  File "C:/Users/Lewis Collins/PycharmProjects/program_05.0.17/Home.py", line 108, in run_language_model
    main.flag_detection()
  File "C:\Users\Lewis Collins\PycharmProjects\program_05.0.17\main_code\main.py", line 169, in flag_detection
    for key, value in str(total_count.items()):
ValueError: not enough values to unpack (expected 2, got 1)

Any suggestions or feedback is welcome, Thanks in advance.

L.C
  • 47
  • 1
  • 1
  • 12
  • 1
    you could use `pickle` or `json` to save your dicts. – Jean-François Fabre Jan 06 '17 at 10:14
  • @Jean-FrançoisFabre I have seen those libraries but I am trying to avoid these and wanting to use built in python libraries if possible. – L.C Jan 06 '17 at 10:21
  • 1
    `csv` is as built-in as `pickle` or `json`: they're standard packages. Even better: write `str(dictionnary)` in a text file, then reload it using `ast.literal_eval` (also standard package). – Jean-François Fabre Jan 06 '17 at 10:24
  • @Jean-FrançoisFabre oh that's good thanks, which do you personally recommend would be best for this and would they work along with tkinter? – L.C Jan 06 '17 at 10:28
  • `json` is a much more suitable choice particularly for exporting a dictionary. – scotty3785 Jan 06 '17 at 10:28
  • `json` is good, but `ast.literal_eval` would allow to reload dictionaries and preserve data type. json only handles string type. – Jean-François Fabre Jan 06 '17 at 10:31
  • @Jean-FrançoisFabre what is 'ast.literal_eval' – L.C Jan 06 '17 at 10:38
  • http://stackoverflow.com/questions/41452232/split-string-based-on-enclosed-brackets/41452294#41452294 – Jean-François Fabre Jan 06 '17 at 12:21
  • You are converting a list of items to a string, and then trying to unpack that single string into two variables. why do you think that `str(total_count.items())` will result in two values? – Bryan Oakley Jan 06 '17 at 12:41
  • @BryanOakley I thought of it in the terms of total_count.items is my key and value and all I'm doing is redefining them to a string rather than a dict, correct me if i'm wrong but from what you are saying I'd have to do a `str(total_count.key())` and a `str(total_count.value())` to get both items into the output. – L.C Jan 06 '17 at 13:11
  • `total_count.items()` returns a single list of tuples. `str(single-list-of-tuples)` returns a single string. I can't give any better advice because I don't understand what you are actually wanting to save: the keys, the values, the entire dictionary, what format, ... – Bryan Oakley Jan 06 '17 at 13:23
  • @BryanOakley What is essentially happening is when the main functionality of my program has finished running 2 text documents are produced one is automatically saved to desktop the second is this document which is supposed to contain the dictionary keys and values what the user chooses to save in any location in a csv format – L.C Jan 06 '17 at 13:31
  • So, it sounds like your real question has nothing to do with tkinter, and is simply "how do I save a dictionary as a csv file"? I recommend completely rewriting your question to show an example of your dictionary, and an example of what you think the csv file should look like. – Bryan Oakley Jan 06 '17 at 14:04
  • @BryanOakley No before i tried to convert to a str I receive an error from tkinter telling me that argument must be str not dict. I will update question and information to better show original tkinter error – L.C Jan 06 '17 at 14:55
  • I see no tkinter error in your question, only the error related to unpacking a string. – Bryan Oakley Jan 06 '17 at 15:05
  • @BryanOakley Question has been updated now and shows the `open() argument 2 must be str, not dict` error – L.C Jan 06 '17 at 15:07

1 Answers1

2

The first problem is this line:

savename = asksaveasfile(file_opt, defaultextension=".csv")

That is simply not how to call asksaveasfile. asksaveasfile doesn't take a dictionary as its first argument. You should call it this way if you want to use the options in file_opt1:

savename = asksaveasfile(defaultextension=".csv", **file_opt)

When you fix that, the next problem is where you try to write with this statement:

savename.write(key, ':', value)

You get this error message: TypeError: write() takes exactly 1 argument (3 given). It means exactly what it says: you need to provide a single argument rather than three arguments. You can solve that by giving write exactly 1 argument:

savename.write("%s: %s" % (key, value))

However, if all you want to do is save a dictionary to a file, the json module makes this quite easy, without having to iterate over the values.

To save as json, change your flag_detection method to look like this:

import json
...
def flag_detection():

    total_count = Counter(traffic_light)

    EWT = tkinter.messagebox.askquestion('File Level', 'Would you like to save')

    file_opt = options = {}
    options['filetypes'] = [('all files', '.*'), ('text files', '.json')]
    options['initialfile'] = 'myfile.json'

    if EWT == 'yes':
        savefile = asksaveasfile(defaultextension=".json", **file_opt)
        json.dump(total_count, savefile)

If you want to save as a csv file, read the documentation on the DictWriter class which works in a similar way.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Thank you, explaining like this takes total sense i can't how i laid out the `savename.write` so wrong when other areas of my code I used the similar argument values of `savename.write("%s: %s" % (key, value))`. Think it's just been one of them weeks were the code is getting too much. But thanks again even your explanation with the json example explains that library a lot more clearer than what I've been reading – L.C Jan 06 '17 at 15:45