Home > Software engineering >  json loading correctly but not saving completely
json loading correctly but not saving completely

Time:12-20

I have run print statements, and everything updates during runtime and the seed and item inventories are working as expected, but the money only loads and won't with the rest of the information

I tried setting up another variable to concatenate all the information and try saving that and I'm getting a "TypeError: 'int' object is not iterable" error. I think this is the issue but I'm unsure how to resolve as most the things I've seen say to use range() or sum(), but I tried that and had the same issue.

import  json, sys


PURCHASE_PRICES = {
    'wood': 4,
    'apple': 2,
    'corn': 10,
    'tomato': 20
}

class Test:
    def __init__(self):

        save_information = {
            'item_inventory': {
                'wood': 1,
                'apple': 1,
                'corn': 1,
                'tomato': 1
            },
            'money': 500

        }

        try:
            print('save found')
            with open('save.txt') as save_file:
                save_information = json.load(save_file)


        except:
            print('no save file found')
            with open('save.txt', 'w') as save_file:
                json.dump(save_information, save_file)
            with open('save.txt', 'r') as save_file:
                save_information = json.load(save_file)

        self.data = save_information

        self.item_inventory = self.data['item_inventory']

        self.money = self.data['money']

        print(self.item_inventory)
        print(self.money)

        current_item = input('enter item to buy "wood:, "apple", "tomato" or "corn" \n> ')

        amount_to_buy = input(f'how many {current_item} would you like to buy\n> ')

        item_price = PURCHASE_PRICES[current_item]
        if self.money >= item_price:
            self.item_inventory[current_item]  = int(amount_to_buy)
            self.money -= int(amount_to_buy) * PURCHASE_PRICES[current_item]

        print(self.item_inventory)
        print(self.money)


        action = input(' press "q" to save and exit\n> ')

        if action == 'q':
            with open('save.txt', 'w') as save_file:
                json.dump(self.data, save_file)
            sys.exit()

if __name__ == '__main__':
    test = Test()
    test()

CodePudding user response:

Using your script I don't get any "TypeError: 'int' object is not iterable error (input "corn" and "1"). But what I see is that you copy "inventory" and "money" like this:

self.item_inventory = self.data['item_inventory']
self.money = self.data['money']

The "inventory" is a dict, therefore the reference is copied and you are manipulating the original object in place. A dictionary is mutable.

The "money" is an int. An integer is immutable. That means you can't alter the int. You create a new one. The original reference in the dict is not updated (print(self.data['money']) to see for yourself.

Then, of course, the value is not saved to the JSON file, as it isn't updated in the dict in the first place.

To "fix" this, either don't copy the money to it's own variable and alter it in the data dictionary or update the value before saving, e.g. with

with open('save.txt', 'w') as save_file:
    self.data['money'] = self.money
    json.dump(self.data, save_file)

There are other - unrelated - bugs in your script. Some examples:

  • It is also a good practice to save JSON files as *.json, etc. But the above should solve your issue.
  • In the expect block it is not needed to create and than read the json. It will be created at the end. Just use the default values already defined.
  • You check for money for one item but the player could buy 123 items.
  • Related