Kind of new to python

Hey guys!

I’m pretty new to python and i’m trying to learn it, so i began a simple project that exports users from my database to a json file.

I however ran in to an issue where it added characters i can’t seem to remove.

As a preview of my code;;

        memberinfo_obj ={
            memberID:{
            "guid": guid,
            "id": memberID,
            "type": "player",
            "avatar": avatarurl,
            "last_username": username,
            "joined_at": joined,
            }
        }
        json.dump(memberinfo_obj, memberfile, indent = 4)

It creates the json file just how i want to have it.
However for some reason addition
The output of this is like this:

{
    "6907364934": {
        "guid": "941745",
        "id": "6907364934",
        "type": "player",
        "avatar": "https://www.kindpng.com/picc/m/78-786207_user-avatar-png-user-avatar-icon-png-transparent.png",
        "last_username": "King11",
        "joined_at": "2022-02-11T17:20:39.303000+00:00"
    }
}{
    "395551754": {
        "guid": "941745",
        "id": "395551754",
        "type": "player",
        "avatar": "https://www.kindpng.com/picc/m/78-786207_user-avatar-png-user-avatar-icon-png-transparent.png",
        "last_username": "Jezia",
        "joined_at": "2022-03-02T10:36:29.432000+00:00"
    }
    }{
        "195551754": {
            "guid": "941745",
            "id": "195551754",
            "type": "admin",
            "avatar": "https://www.kindpng.com/picc/m/78-786207_user-avatar-png-user-avatar-icon-png-transparent.png",
            "last_username": "illinux",
            "joined_at": "2022-01-011T10:36:29.432000+00:00"
        }
}

As you can see it places additional }{'s in there.
I need to replace these with a , to make it a valid json file.
Can anyone tell me what i’ve done wrong? I have no idea what i did wrong.

Thanks for including your code and output as text in properly formatted code blocks, and fairly clearly describing your problem.

While there isn’t enough context included to be sure, it seems very likely based on the code you have, your result and your indent levels that you’re calling json.dump() inside a loop, and writing a new memberinfo_obj to the file each time. Thus, each time you’re writing a new dictionary with a single element, rather than one write of one single dictionary with all the elements, which is not what you want.

Instead, pull the initial creation of memberinfo_obj outside the loop, or make it a dict comprehension, add each item to the dict inside the loop, and then after the loop completes, write the whole dictionary as JSON in one go. In addition to actually doing what you want, this is also more efficient, as it only requires one write instead of many small ones, and keeps the file open for shorter.

So, instead of something like what I’m guessing you have now, e.g.

with open("members.json", "w", encoding="UTF-8") as memberfile:
    for member_id, guid, ... in members:
        memberinfo_obj = {
            member_id: {
                "guid": guid,
                "id": member_id,
                ...
                }
            }
        json.dump(memberinfo_obj, memberfile)

you can instead do just

memberinfo_obj = {
    member_id: {
        "guid": guid,
        "id": member_id,
        ...}
    for member_id, guid, ... in members}
with open("members.json", "w", encoding="UTF-8") as memberfile:
    json.dump(memberinfo_obj, memberfile)

Hey there!
Yeah you pretty much described the issue there for me hehe.

After trying what you suggested, it won’t implement all data just a singular one (properly formatted though)

I’m assuming thats cause i am still having the memberobject write within the loop, and moved the with open and json.dum outside of the loop, how do i correctly write to the memberobject, with keeping all the data i iterate over

Please provide a minimum reproducible example of the code you’re using and a sample of the affected output. I tested with

members = ((123, 551), (124, 552))

and

memberinfo_obj = {
    member_id: {
        "guid": guid,
        "id": member_id}
    for member_id, guid in members}
json.dumps(memberinfo_obj)

outputs the expected

'{"123": {"guid": 551, "id": 123}, "124": {"guid": 552, "id": 124}}'

Therefore, it would seem there is an issue with your code—some possibilities include either there’s something going on with your dict comprehension, the items are being added to the dict all with the same key, they aren’t being added to the same dict at all, the dict is being written after only one item is added (e.g. json.dump is still at the wrong indent level), or the wrong dict/a subset of the dict is being written.

Thank you for the quick response.

Yes i do believe i am looking at this all wrong.

The previous code i attempted to run was ;;

        memberinfo_obj ={
            memberID:{
            "guid": guid,
            "id": memberID,
            "type": "Player",
            "avatar": avatarurl,
            "last_username": username,
            "joined_at": joined}
            for memberID, guid, avatarurl, username, joined in bot.gateway.session(GameServerId).members}
with open('D:\Mdata/metrics/{0}.json'.format(servername),'w') as memberfile:
        json.dump(memberinfo_obj, memberfile, indent = 4)

Where the output became

{
    "6907364934": {
        "guid": "941745",
        "id": "6907364934",
        "type": "player",
        "avatar": "https://www.kindpng.com/picc/m/78-786207_user-avatar-png-user-avatar-icon-png-transparent.png",
        "last_username": "King11",
        "joined_at": "2022-02-11T17:20:39.303000+00:00"
    }
}

I do have to note, that above the creation of the memberinfo_obj , i am running a loop to get all the information from the database.

I can only guess at what you might be doing, because you haven’t provided either your current code or your output, nor was enough context shown in the original example to even know for sure what you were doing before. However, if you follow the approach I outlined and detailed above, constructing memberinfo_obj using a dict comprehension (which can be done neatly all in one logical line), you first build memberinfo_obj (which seems to be where you’re running into your problem here), then write it out. This not only fixes the problem, but is simpler, cleaner and more performant code.

If you’re confused by the use of a comprehension, you can do the same thing with a regular for loop (that I presume you’re already using), not quite as neatly and efficiently, but still correctly (I actually included this example in a draft of my initial answer, but ended up removing it to make it shorter and more focused).

memberinfo_obj = {}
for member_id, guid, ... in members:
    memberinfo_obj[member_id] = {
        "guid": guid,
        "id": member_id,
        ...}
with open("members.json", "w", encoding="UTF-8") as memberfile:
    json.dump(memberinfo_obj, memberfile)

Thank you for the explanation, i appreciate the time, and effort put in to assisting me with this, with this guidance, i am going to approach it differently, and rewrite the looping function with the correct logic.

Thank you @CAM-Gerlach

As I’ve stated previously, we can only guess at what your code is doing here, because this critical context (that is very likely the root cause of the issue here) is inexplicably still not included.

While not quite a self-contained minimally reproducible example, I was able to make it into one with only a couple small tweaks—replacing gateway.session(GameServerId).members with example_members, which I defined to be (roughly following your schema):

example_members = ((1, 111, "testurl1", "user1", 2021),
                   (2, 222, "testurl2", "user2", 2022))

and using json.dumps instead of json.dump for more easily readible output, plus removing the out of context indent level, which gives us

memberinfo_obj = {
    memberID: {
    "guid": guid,
    "id": memberID,
    "type": "Player",
    "avatar": avatarurl,
    "last_username": username,
    "joined_at": joined,
    }
    for memberID, guid, avatarurl, username, joined in example_members}
print(json.dumps(memberinfo_obj, indent = 4))

This prints exactly the desired output,

{
    "1": {
        "guid": 111,
        "id": 1,
        "type": "Player",
        "avatar": "testurl1",
        "last_username": "user1",
        "joined_at": 2021
    },
    "2": {
        "guid": 222,
        "id": 2,
        "type": "Player",
        "avatar": "testurl2",
        "last_username": "user2",
        "joined_at": 2022
    }
}

Therefore, either your input data is not in this form, or there’s something in the not-provided context I’ve asked for (most likely the enclosing for loop, the purpose of which is not entirely clear) that is not behaving as it should.

Also, to note, there are a couple issues with your open() call:

First, you must always use encoding="UTF-8" (as in my previous example above) when reading and writing JSON (and always doing so in general when reading and writing, or otherwise explicitly declaring your encoding, is usually a good idea), or the output may (or in the case of your Windows machine, will) not be in the correct encoding. Second, there is a strange escaped \M character at the beginning of your path, which appears to be spurious—did you mean to use a forward slash instead? Finally, instead of using Python 2.6-style ordinal placeholders with format, just use an f-string—i.e. instead of

'D:/Mdata/metrics/{0}.json'.format(servername)

you can just do

f'D:/Mdata/metrics/{servername}.json'
1 Like