IAmAHuman
IAmAHuman

Reputation: 309

Remove element from JSON Python

I'm trying to make a command for my discord bot that deletes a so called "faction" from a server. The factions are stored in a neat JSON like this

{
    "Meme Faction": {
        "members": [],
        "owner": 429935667737264139,
        "description": "This is the description :smile:",
        "member role": 773580603072839710,
        "owner role": 773580603605516290
    },
    "Gamer Faction": {
        "members": [],
        "owner": 429935667737264139,
        "description": "This is the description :smile:",
        "member role": 773580603072839710,
        "owner role": 773580603605516290
    }
}

Here's the code that's supposed to remove a faction:

@commands.command(aliases=["d"])
async def delete(self, ctx, *, name: str):
    with open("configs/factions.json", "r+") as f:
        factions_json = json.load(f)
        factions_list = list(factions_json.keys()) # loads JSON keys as list

        name_capital = name.title()
        if name_capital in factions_list:
            member_role = ctx.guild.get_role(factions_json[name_capital]["member role"])
            owner_role = ctx.guild.get_role(factions_json[name_capital]["owner role"]) 

            await member_role.delete() # deletes faction role
            await owner_role.delete() # deletes faction owner role

            # JSON remove code
            factions_json.pop(name_capital) 
            f.seek(0)
            json.dump(factions_json, f, indent=4)

            await ctx.message.add_reaction("✅")

The issue is, instead of removing the faction from the JSON, it just appends another version of the JSON without the faction to the end. Like this:

{
    "Meme Faction": {
        "members": [],
        "owner": 429935667737264139,
        "description": "This is the description :smile:",
        "member role": 773580603072839710,
        "owner role": 773580603605516290
    },
    "Gamer Faction": {
        "members": [],
        "owner": 429935667737264139,
        "description": "This is the description :smile:",
        "member role": 773580603072839710,
        "owner role": 773580603605516290
    }
}{
    "Meme Faction": {
        "members": [],
        "owner": 429935667737264139,
        "description": "This is the description :smile:",
        "member role": 773580603072839710,
        "owner role": 773580603605516290
    },
}

How can I overwrite the JSON instead of appending to it?

Upvotes: 0

Views: 120

Answers (1)

pho
pho

Reputation: 25490

When you open a file in mode r+, you open it for reading and writing.

Then, you read the file, so the stream position moves to the end of the file.

Then, you write to the file, so it writes at the current stream position, which is the end of the file.

To fix this, you have two options:

Option 1:

Seek the position to the starting of the file using f.seek(0). Then write to the file. The problem with this is that it will only overwrite as much of the file as needs to be overwritten to dump the new json. The rest of the file won't be overwritten, so you'll end up with garbled json anyway. To fix this, you will need to truncate the rest of the file.

with open('factions.json', 'r+') as f:
    j = json.load(f)
    j.pop("Meme Faction")
    f.seek(0)
    json.dump(j, f, indent=4)
    f.truncate()

Gives the output:

{
    "Gamer Faction": {
        "members": [],
        "owner": 429935667737264139,
        "description": "This is the description :smile:",
        "member role": 773580603072839710,
        "owner role": 773580603605516290
    }
}

Option 2

Close the original file handle and open a new one for write-only. Then write to the file.

with open('factions.json', 'r+') as f:
    j = json.load(f)

j.pop("Meme Faction")
with open('factions.json', 'w') as f:
    json.dump(j, f, indent=4)

Gives the output:

{
    "Gamer Faction": {
        "members": [],
        "owner": 429935667737264139,
        "description": "This is the description :smile:",
        "member role": 773580603072839710,
        "owner role": 773580603605516290
    }
}

Upvotes: 2

Related Questions