Search code examples
pythonfileherokudiscorddiscord.py

Why can't heroku get the text files on my folder while running my program?


I am doing a simple discord bot with python and I'm using heroku to host it. I have some commands that return a big text, so I put these texts on separate .txt files and organized all those files in a single folder called "files". Then I used the code to access and read those files. Everything works fine when I am hosting the bot, but heroku always returns a "FileNotFoundError" when he is hosting.

The full error message:

Ignoring exception in command helpie:
Traceback (most recent call last):
File "/app/.heroku/python/lib/python3.10/site-packages/discord/ext/commands/core.py", line 85, in wrapped
ret = await coro(*args, **kwargs)
File "/app/main.py", line 27, in helpie
helpmessage = open(".\files\helpMessage.txt", "r", encoding = "utf-8")
FileNotFoundError: [Errno 2] No such file or directory: '.\x0ciles\\helpMessage.txt'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "/app/.heroku/python/lib/python3.10/site-packages/discord/ext/commands/bot.py", line 939, in invoke
await ctx.command.invoke(ctx)
File "/app/.heroku/python/lib/python3.10/site-packages/discord/ext/commands/core.py", line 863, in invoke
await injected(*ctx.args, **ctx.kwargs)
File "/app/.heroku/python/lib/python3.10/site-packages/discord/ext/commands/core.py", line 94, in wrapped
raise CommandInvokeError(exc) from exc
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: FileNotFoundError: [Errno 2] No such file or directory: '.\x0ciles\\helpMessage.txt'

Here is one of the commands that use a .txt file. This code is on the main.py file, that heroku is reading.

@bot.command()
async def helpie(ctx):
    helpmessage = open(".\files\helpMessage.txt", "r", encoding = "utf-8")
    await ctx.send(helpmessage.read())
    helpmessage.close()

Here is the tree of the root folder of the program and all it's files:

C:.
│   .gitignore
│   main.py
│   Procfile
│   README.md
│   requirements.txt
│   runtime.txt
│
├───.vscode
└───files
        bot icon.png
        geraldoMessage.txt
        helpMessage.txt

I don't know if it is necessary, but I will also include the content of the "requirements.txt" and "Procfile".

Procfile:

worker: python main.py

requirements.txt

discord.py
asyncio

Thank you for the help.


Solution

  • I suspect a more complete error would be something like this:

    No such file or directory: '.\x0ciles\\helpMessage.txt'
    

    The immediate issue is probably that you're accidentally using an escape sequence by including \f in your string, which indicates an ASCII form feed.

    Note that the path has been mangled. You could us a raw string here:

    open(r".\files\helpMessage.txt", "r", encoding = "utf-8")
    #    ^ raw string
    

    Or you could change how you define that path. Forward slashes are safer than backslashes, and joining individual path components together using pathlib or os.path is safer still.

    I don't think this is your immediate issue, but your path is also relative to whatever the working directory happens to be. I suggest making it relative to a known location, e.g. the root directory of your project.

    Putting that together, try something like this (using pathlib):

    from pathlib import Path
    
    # This will point to the right directory no matter what the working directory is
    root_path = Path(__file__).resolve().parent
    
    
    @bot.command()
    async def helpie(ctx):
        helpmessage = open(root_path / "files" / "helpMessage.txt", "r", encoding = "utf-8")
        #                            ^         ^ safely joining components
        #                  ^^^^^^^^^ known path
        await ctx.send(helpmessage.read())
        helpmessage.close()
    

    or like this (using os.path):

    import os.path
    
    root_path = os.path.dirname(os.path.abspath(__file__))
    
    
    @bot.command()
    async def helpie(ctx):
        helpmessage = open(os.path.join(root_path, "files", "helpMessage.txt"), "r", encoding = "utf-8")
        #                               ^^^^^^^^^ known path
        #                  ^^^^^^^^^^^^ safely joining components
        await ctx.send(helpmessage.read())
        helpmessage.close()