Simpler the json

 import codecs

class fileFormat():
    def loads(self, file):
        input = open( file, "rU" )
        final={}
        key=None
        sign=1
        firstLine=True
        for line in input:
            striped=line.strip()
            if firstLine:
                firstLine=False
            else:    
                if not key:
                    key=striped
                    if key:
                        final[key]={}
                else:
                    if striped=='':
                        key=None
                    else:
                        temp=striped.split("=")
                        if len(temp)>1:
                            final[key][temp[0]]=self.parse(temp[1])
        return final
        
    def parse(self, element):
        element=element.strip()
        #negatives for later...
        sign=1
        if element.startswith("-"): 
            element=element.strip("-")
            sign=-1
        else:
            sign=1
        #for strngs in ''    
        if element.startswith("'"): 
            return element.strip("'")
        #for strings in ""    
        if element.startswith('"'): 
            return element.strip('"')
        #for ints   
        if element.isdigit(): 
            return int(element)*sign
        #for floats     
        if "." in element:    
            test=element.split(".")
            if test[0].isdigit() and test[1].isdigit():
                return float(element)*float(sign)
        #for lists
        if element.startswith('['):
            list=element.strip('[]')
            list=list.split(',')
            outlist=[]
            for item in list:
                outlist.append(self.parse(item))
            return outlist
        #for dicts
        if element.startswith('{'):
            dic=element.strip('{}')
            dic=dic.split(',')
            outdict={}
            for item in dic:
                key_value=item.split(':')   
                key_value[0]=key_value[0].strip()
                key_value[0]=key_value[0].strip('"')
                key_value[0]=key_value[0].strip("'")
                outdict[key_value[0].strip()]=self.parse(key_value[1])
            return outdict    
        #for strings with no quotes... or anything else    
        return str(element)
        
    def dumps(self, input, file):
        output = open( file, "w" )
        output.write('#this game file format\n')
        for item in input:
            output.write(item+'\n')
            for subitem in input[item]:
                output.write(subitem+'='+str(input[item][subitem])+'\n')
            output.write('\n')

This is a code loading and dumping data into a file format that I creared.

Why have I made this? Well, I used to use json and it looked as a perfect human editable format for some time, but when I showed some files to a non-programer friend of mine, she said that it has too many brackets, quotes and the formating just makes it all look like a mess. An hour and five cups of coffe later we had a new file format that Iwe bothe were happy with.

How it look.

Let’s take a look at some data that I want to store:

Items={"sword":{"damage":[5,10], "slot":"r_hand", "icon":"sword01.png"}, "shield":{"armor":5, "slot":"l_hand", "icon":"shield.png"} }

It is readeable, but it could be simpler.This is thesame data using my format

#this game file format
sword
damage=[5,10]
slot=r_hand
icon=sword01.png

shield
armor=5
slot=l_hand
icon=shield.png

So, the first line in a file is a comment, always. This is done not to bother with BOM.
Every line that has no ‘=’ symbol is a ‘main key’, the end of values for a main key should end with a blank line. There can be any number of key-value entries under any main key, the ‘=’ symbol is used to determine what is a key and what is a value. The value can be a string (with optional quotes or double quotes), a int (also negative), a float (if it has a dot ‘.’ and both sides of a dot are numbers), a list (has to start with ‘[’ and end with ‘]’, values in a list can be ints, floats and strings), a dict (has to start with ‘{’ and end with ‘}’, values in a list can be ints, floats and strings, key-values are separated with ‘:’, just like a default Python dict).
You should not nest lists or dicts inside other lists or dicts - the parser could be made to understand these, but people reading the files may not.

This is not universal, this is not fail-safe, this is not very fast - but it works for most cases and it will only ever return a dict and will not execute any code found in the loaded files. The idea was to make a file format with minimal meta-data and ‘glifs’.

I’d welcome opinions and suggestions.

You might want to take a look at YAML:

  • minimal formatting
  • very fast when using the compiled extension (but has pure Python as a fallback)
  • has a safe-loading mode that will only load basic (safe) types

Your example here would look like:

#this game file format
sword:
  damage: [5,10]
  slot: r_hand
  icon: sword01.png

shield:
  armor: 5
  slot: l_hand
  icon: shield.png

You will also need to think of the use case as well. Will the non-programming friend ever need to look at the file being saved? If not then json or yaml is fine.

YAML would be good, but the problem with it is that you can write lists in brackets with commas or in new lines with ‘-’ and that could be confusing, same with dicts. Indentation is also not welcome (how many spaces? can I use tabs? -you can’t know that just by looking at the file). I’d like to have just one way to do thing.
Maybe if I didn’t writhe the parser I’d use yaml, but now? Would going to yaml make my files more readable? I don’t think so, but it’s still good to know about yaml for the future.

Will non-programers want to edit these files? I do hope so - otherwise I’d put all the data into a sqlite database.

Doesn’t python also have an ini module as well?

Yes, through the ConfigParser module, which accepts a format like this:

[section]
setting=1
other=test.png

[test]
key = value

Also, keep in mind that JSON is technically a subset of YAML 1.2 (a JSON document parses as valid YAML). There are multiple ways you can format using YAML, so it’s quite flexible.