Home > Software engineering >  Multipurpose function to create and append json using specified base python
Multipurpose function to create and append json using specified base python

Time:11-03

Can someone help me with my code below? The main purpose of this is to use the data_manager class as a way to store data into a json file.

After being created, a json file named with the specified name, containing a json base, also named with the specified name is created

The major function that handles the majority of the logic is in write_to_json function inside the data_manager class

def write_to_json(self, new_data, base = ""):

There are four major use cases that I am trying to handle:

where match means the item key is found in the file data and base is where we are trying to add the data to (an existing tier / base) (if blank, add it to base)

  • Case 1 - No match, no base: add to main list

  • Case 2 - No match, base: add to base

  • Case 3 - Match, no base: check if value is different and if so, replace value in main list

  • Case 4 - Match, base, check if value is different and if so, replace value in base list

Right now I have case 1 and 3 working, but I am having issues with 2 and 4.

I have been trying many different ways to code this and keep running into problems.

import os
import sys
import json

class file_manager:
    def set_file_contents(self, file_name, contents):
        file = open(file_name, "w")
        file.write(contents)
        file.close()

    def set_file_contents_append(self, file_name, contents):
        if not os.path.exists(file_name):
            open(file_name, 'a').close()
        file = open(file_name, "a")
        file.write(contents)
        file.close()




    def get_file_size(self,file_name):
        return os.path.getsize(file_name)

    def get_file_content_json(self,file_name):
        return json.load(open(file_name)) if self.get_file_size(file_name) != 0 else None
        
class data_manager(file_manager):
    data_file = None
    json_data = []
    data_name = None
    def __init__(self,data_name):
        self.data_base = data_name
        self.data_file = data_name   '.json'
        self.create_data_file()

    def create_base(self,base):
        data = {base:[]}      
        self.set_file_contents(self.data_file,json.dumps(data,indent=4))
  
    def create_data_file(self):
        self.create_base(self.data_base)

    def check_file_size(self):
        print(self.get_file_size(self.data_file))

    def check_if_exist(self, data_name):
        file_data = self.get_file_content_json(self.data_file) 
        data_value = False
        for item in file_data[self.data_base]:
            if data_name in item.keys():
                print(f'{data_name}: {item[data_name]}')
                data_value = True
        return data_value

    def get_data_value(self,data_name):
        d = self.get_file_content_json(self.data_file) 
        d = d[self.data_base]
        print(data_name)
        items = []
        for item in self.item_generator(d,data_name):
            print(f'returning value = {item}')
            items.append(item)
        return dict(items[0]) if items else None

    def item_generator(self,json_input, lookup_key):
        if isinstance(json_input, dict):
            for key, value in json_input.items():
                if key == lookup_key:      
                    yield {key:value} 
                else:
                    yield from self.item_generator(value, lookup_key)
        elif isinstance(json_input, list):
            for item in json_input:
                yield from self.item_generator(item, lookup_key)
                
    def replace_data_value_json(self, file_data, data_name, data_value):
        for item in file_data:
            if data_name in item.keys():
                item[data_name] = data_value
        return file_data

    def set_data_value(self, data_name, data_value):
        file_data = self.get_file_content_json(self.data_file) 
        for item in file_data[self.data_base]:
            if data_name in item.keys():
                item[data_name] = data_value
        self.set_file_contents(self.data_file,json.dumps(file_data,indent=4))

    def view_all_data(self):
        file_data = self.get_file_content_json(self.data_file) 
        print((file_data))
     
    def remove_data_item(self, data_name):
        file_data = self.get_file_content_json(self.data_file) 
        print(file_data)
        for element in file_data[self.data_base]:
            if data_name in element:
                del element[data_name]
        self.set_file_contents(self.data_file,json.dumps(file_data,indent=4).replace('{}','').replace('\{\},','') )

    def prettyjson(self,data):
        return json.dumps(data,indent=4)

    def compare_equal(self, value1, value2):
        print(f'{value1} really vs {value2}')
        return True if str(value1) == str(value2) else False

    def write_to_json(self, new_data, base = ""):
        file_data = self.get_file_content_json(self.data_file) 

        #print(f'Data before:\n{json.dumps(file_data,indent=4)}')
        base = self.data_base if base == "" else base
        #print(list(file_data) - file_data[base])
    

        print(f'Complete file:\n{self.prettyjson(file_data)}')

        #file_starting_from_base = list(file_data[data_name])
        print('Starting from base')
        print(self.prettyjson(file_data[self.data_base]))
       
        file_data_before = ([item for item in file_data if item not in file_data[self.data_base]])
        #print(file_data_before)

        for data_item in new_data:
            match_found = False
            index = None
            value_from_name = self.get_data_value(data_item)
            value_from_name = list(value_from_name) if value_from_name else None
           # print(f'before: {value_from_name} {type(value_from_name)} {list(value_from_name)} ')
            value_from_name = value_from_name[0] if value_from_name and value_from_name[0] else None
            value_from_name_found = True if value_from_name else False

            if value_from_name_found:
                print(f'found: {value_from_name}')
                match_found = True
            
            #OLD METHOD USED TO FIND INDEX
            # #if base != self.data_base:
            # index = 0
            # for item in file_data[self.data_base]:
            #     print(f'{list(item.keys())[0]} vs {base}')
            #     if str(base) in list(item.keys())[0]:
            #         print(f'MATCH FOUND = {base} = {list(item.keys())[0]}')#: {item.values()} {index}')
            #         match_found = True
            #         break
            #     index  = 1
            # print(index)
            #     #return
            
            data_single_item = {data_item:new_data[data_item]}

            if not match_found:
                #Case 1 - No match, no base: add to main list
                if base == self.data_base:
                    file_data[self.data_base].append(data_single_item)

                else:
                #Case 2 - No match, base: add to base
                    print(f'ADD {data_single_item} TO {file_data[self.data_base]} starting from {base}')

                    #possible idea: create base and try again adding values again
                    #self.create_base(base)
                    #self.write_to_json(data_single_item,base)

                    #file_data[self.data_base].append(data_single_item)     #broken 
                       
                    #old working method, broken without index
                    #file_data[self.data_base][index][base].append(data_single_item)

            #MATCH FOUND
            else:
                #Case 3 - Match, no base: check if value is different and if so, replace value in main list
                if base == self.data_base:

                    file_data[base] = self.replace_data_value_json(file_data[base],str(data_item),new_data[data_item])
                    pass

                else:
                #Case 4 - Match, base, check if value is different and if so, replace value in base list
                    print(f'data = {self.get_data_value(data_item)}' )
                    # print(f'check {new_data[data_item]} vs {list(self.get_data_value(data_item))[0]}')

                    value_from_name = self.get_data_value(data_item)
                    value_from_name = list(value_from_name) if value_from_name else None
                    print(f'before: {value_from_name} {type(value_from_name)} {list(value_from_name)} ')
                    value_from_name = value_from_name[0] if value_from_name and value_from_name[0] else None
                    value_from_name_found = True if value_from_name else False

                    if value_from_name_found and (not self.compare_equal( new_data[data_item], value_from_name ) ):
                        print(f'{new_data[data_item]} NOT EQUAL TO {value_from_name}') 
                        # change value to new value

                        #file_data[self.data_base][base].append(data_single_item)
                        #print(f'add {data_single_item}')

            final_output = {self.data_base:file_data[self.data_base]}
            self.set_file_contents(self.data_file,self.prettyjson(final_output))

    def add_data_single(self, data_name, data_value, base):
        new_data_item = {data_name: data_value}
        self.write_to_json(new_data_item, base)
    
    def add_data_multiple(self,data,base=""):
        self.write_to_json(data,base)


# CREATE 'people.json' AND create json base matching name in file ( { "people": [] } )
test = data_manager('people') 

# CREATE 3 ITEMS STARTING IN MAIN BASE
test.write_to_json({'John':[], 'Alex':[], 'Samantha':[]}) # CASE 1


# SHOULD ATTEMPT TO ADD VALUES TO BASE 'john', 
# if dictionary key matches, check if key matches
# if key and value match, do nothing and do not overwrite file)
# if key matches and value does not, change the value of the item matching the key starting from base 'John'
# if dictionary key does not match, add full dictionary item to base
test.write_to_json({"Favorite-Food":"tacos" , "Age":45}, "John")  # CASE 2

# CREATE 
#test.write_to_json({'Example2-Sub1':44},'Example2') 

CodePudding user response:

I think/hope you might have some unwanted lists in your json and that when you indicate you are hoping for:

{
    "people": [
        {"John": [{"favorite-food": "tacos", "Age": 45}]},
        {"Alex": []},
        {"Samantha": []}
    ]
}

what you really want is:

{
    "people": {
        "John": {"favorite-food": "tacos", "Age": 45}
    },
    {"Alex": {}},
    {"Samantha": {}}
}

If that is what you want in the end, then this code based on merging dictionaries via the {**a, **b} method is the way forward:

import json
import os

class data_manager():
    BASE_COLLECTIONS_FOLDER = "./data"

    def __init__(self, collection_name):
        self.collection_name = collection_name
        self.collection_file_path = f"{self.BASE_COLLECTIONS_FOLDER}/{self.collection_name}.json"
        self.collection = {}
        self.ensure_collection()
        self.load_collection()

    def ensure_collection(self):
        if os.path.isfile(self.collection_file_path):
            return

        os.makedirs(self.BASE_COLLECTIONS_FOLDER, exist_ok=True)
        self.save_collection()

    def load_collection(self):
        with open(self.collection_file_path, "r", encoding="utf-8") as collection_file:
            self.collection = json.load(collection_file)[self.collection_name]

    def save_collection(self):
        with open(self.collection_file_path, "w", encoding="utf-8") as collection_file:
            json.dump({self.collection_name: self.collection}, collection_file, indent=4)

    def write_to_json(self, data, key=None):
        if not key:
            self.collection = {**self.collection, **data}
        else:
            self.collection[key] = {**self.collection.get(key, {}), **data}
        self.save_collection()

people = data_manager("people")
people.write_to_json({"John": {}, "Alex": {}, "Samantha": {}})
people.write_to_json({"Favorite-Food": "tacos", "Age":45}, "John")
people.write_to_json({"Parents": {"Mother": "Britney", "Dad": "Adam"}}, "John") 
people.write_to_json({"Parents": {"Mother": "Britney", "Dad": "John"}}, "John")
people.write_to_json({"Bob": {"name": "not bob"}})
people.write_to_json({"Bob": {"name": "bob"}})
people.write_to_json({"Example2-Sub1": 44}, "Example2") 

Running this will result in a file who's contents are:

{
    "people": {
        "John": {
            "Favorite-Food": "tacos",
            "Age": 45,
            "Parents": {
                "Mother": "Britney",
                "Dad": "John"
            }
        },
        "Alex": {},
        "Samantha": {},
        "Example2": {
            "Example2-Sub1": 44
        },
        "Bob": {
            "name": "bob"
        }
    }
}
  • Related