1

So, I have a JSON file, let's call it my_file.json, that contains some information:

[
   {
      "user": 0,
      "infos": []
   },
   {
      "user": 1,
      "infos": []
   }
]

On my BOT, I want to create a function to access the "infos" of a user id:

import json

@bot.command()
async def getinfo(ctx, *, user_id):
    user_id = int(user_id)
    with open("my_file.json") as f:
        for _ in json.load(f):
            if _["user"] == user_id:
                # HERE I WANT TO SEND THE CONTENTS OF "infos" OF THE 
                # CORRESPONDING USER ID IN A FILE, EACH LIST ITEM SEPERATED BY 
                # A NEWLINE

So I want the BOT to send the file containing all the items of the "infos" list of the corresponding user id, each of them separated by a newline, but I don't want the file to be saved on my computer. Is this possible?

TheOneMusic
  • 1,776
  • 3
  • 15
  • 39

2 Answers2

2

I believe StringIO is what you are looking for.

Examples: python PIL image how to save image to a buffer so can be used later?

Manual: https://docs.python.org/2/library/stringio.html

Alex R
  • 77
  • 5
2

It is possible!

The key is using StringIO instead of a regular file.

Solution

from os import linesep
import io
import json
from discord import File


@bot.command()
async def getinfo(ctx, *, user_id):
    user_id = int(user_id)
    with open("my_file.json") as fdata:
        for _ in json.load(fdata):
            if _["user"] == user_id:
                f = io.StringIO(linesep.join(_["info"]))
                await ctx.channel.send(content="info", file=File(fp=f, filename="user_info.txt"))

Sidenotes

Your data structure might not be the right one, if you can organize your data this way in the json file:

{
    "0": {"info": []},
    "1": {"info": []},
    ...
}

Then the solution to your problem is both easier to code and faster to run, because by putting your users in a dictionary indexed by their IDs you won't have to iterate over a list to find the user you want:

from os import linesep
import io
import json
from discord import File


@bot.command()
async def getinfo(ctx, *, user_id):
    with open("my_file.json") as fdata:
        users = json.load(fdata)
        if user_id in users:
            f = io.StringIO(linesep.join(users[user_id]["info"]))
            await ctx.channel.send(content="info", file=File(fp=f, filename="user_info.txt"))

EDIT1: to use string as keys instead of int in the sidenote solution

EDIT2: added \r\n to have functional newlines on Windows

EDIT3: now using os.linesep to get functional line breaks on every OS

Inspi
  • 530
  • 1
  • 4
  • 19
  • 1
    you're right we can't use int directly as keys, however you can convert the user IDs to string when putting them in the JSON, and when you use getinfo you won't have to convert the user_id you want to an int. As for the new lines this is weird it should work, i'll investigate a bit to see if it's an error from me – Inspi Jun 14 '19 at 17:10
  • 1
    hum I would need to see your usecase because you don't need to compare numbers in the functions you posted here. Sidenote: i figured why the newlines aren't working: your bot is running on Windows ! (am i right?) I'm looking for a fix that work on every OS, i'll update my post soon – Inspi Jun 14 '19 at 17:16