Hi, I coded a game in python and I need to load images so I used os.path.join since I was told that was cross-compatible. However, when my friend( who is on windows ) tried to run the game, he was met with my exception_handling message. I have put try except whenever an image is loaded and he was met with my inbuilt error message. We checked everything and he has the correct files, in the correct place and everything should work but it doesn’t. You can check my game’s code here The only thing that I believe is the issue is that I used relative paths but he is running main.py from the same directory that the Assets folder is in, so I think the relative paths should work, but they don’t. I don’t really know how python differs on operating systems so I do need help on this. Thanks!
#🔒 Os.path.join doesn’t work the same on MacOS vs Windows
286 messages · Page 1 of 1 (latest)
@thorny dune
Remember to:
- Ask your Python question, not if you can ask or if there's an expert who can help.
- Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
- Explain what you expect to happen and what actually happens.
:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.
what error specifically?
if you want to make sure your paths are resolved to the scripts directory, you should use __file__ variable, that contains the path to the script file that variable is used in
typically you have something like:
from pathlib import Path
script_dir = Path(__file__).absolute().parent
``` and `script_dir` is then the absolute path to the scripts directory.
or similar in os.path:
script_dir = os.path.dirname(os.path.abspath(__file__))
``` I think
haven't used os.path for a while
Hi, the error isn’t given in the terminal since my script handles it and from my script I can see it’s a FileNotFound since that’s the only error my script handles
Hi, I did use this, but it refused to run on my Mac
is your script handling your errors? or hiding them?
if it's the latter, don't do that. let the script fail and show or log the entire traceback
what do you meam, it refused?
again no errors?
Basically, whenever I need to load an image, I have a try except thing that handles FileNotFound errors, so I don’t see the actual log and it rather displays a message on the screen saying that [this image] wasn’t found
pygame.transform.scale(pygame.image.load(os.path.join("Assets", "Mute.png"))
``` this is a relative path.
you need to add the example script_wdir at the beginning.
ideally you'd do: os.path.join(script_dir, "Assets", "Mute.png")
where script_dir is defined at the top of you Main.py file
Hi, I did that, but when I ran it on my Mac, it gave me the error on the screen that I had programmed
you need tracebacks. don't hide your errors
So you are saying I should remove my try except thing and run the code with script_dir on my Mac and tell you the error?
you could use the logging module, to log your exceptions to a file
Also, how you do you format the code on discord?
Please elaborate, I have never used the logging module
to use the logger in the simplest way, in any python file you simply add these two lines:
from logging import getLogger
logger = getLogger(__name__)
and in your Main.py as early as possible you do the above and additionally:
import os
import logging
script_dir = os.path.dirname(os.path.abspath(__file__))
logfile = os.path.join(script_dir, 'mylog.log')
logging.basicConfig(filename=logfile, level=logging.INFO)
!code
then you can do stuff like:
try:
...
except SomeException:
logger.exception('some extra message here')
that shoul log the message with the entire exception attached to it
Ok, just to check I should put os.path.join(script_dir, “Assets”, “Mute.png”)
Right?
yes, assuming script_dir is defined as above, in your Main.py
the __file__ variable is always the path to the script file, where you use that variable in... so if you define script_dir in a subfolder, you may need to add a .. to get up one directory: os.path.join(script_dir, '..', 'Assets', 'Mute.png')
personally I prefer to just have a centralized function, and resolve everything from there.
oh, ok
I'd basically do: pygame.image.load(ref("Assets/Mute.png"))
and make sure to use forward slashes: / .. as those work on windows as well...
then the ref function might just use the path together with join and __file__ to resolve to the correct location.
I've imported logging and added the earlier code you provided at the top of main.py but it says that logger isn't defined
you also need to add that
sorry, forgot about that, my bad
that actually creates a logger. and you add those two lines to every python file where you need a logger
the basicConfig only goes in your Main.py though. that you only do once on startup 🙂
ok! I did that and I tried it with my mutesymbol, but I got the error it wasn't associated without a value
as s side note: you should probably add .idea/ and .DS_Store to your gitignore and remove them from git (using git rm -rf --cached .idea .DS_Store ) ... those shouldn' really go into git 😄
this is my code
thank you
did that
oh any __pycache__ as well
muteSymbol = pygame.transform.scale(pygame.image.load(os.path.join(script_dir, "..", "Assets", "Mute.png")), (70, 50))
there is a chance that those pycache files actually make it not work on windows
where? in the Main.py?
That sometimes is there by default too
yes
pycache gets generated by python, but it's version and platform specific... so if you got a Mac pycache, and it's then used on windows.. .it may fail
ok
you don't need the ".." in Main.py
I will git.ignore that
oh, ok
it loaded just fine
I told you that the extra ".." is only needed, if the python file you define the script_dir in happens to be in a subfolder (relative to the Assets folder)
in doubt: Always Be Printing
When i used that, a log was generated
also, I need to load stuff inside Draw.py, which is inside, "Drawing" so will i need ".."?
mylog.log should probably be in gitignore as well 😄
in that case, yes.
you could also like suggested, have a utility function somewhere, that all locations can import.
please, i mean if you opened a pull request, that would be easier, but please do tell
I would love to have that kind of function, I tried, but I couldn't figure out how that'd work
I ran this command but nothing got added to my git.ignore file
we could put it in File_Handling, in Utils.py or something like that:
import os
file_handling_dir = os.path.dirname(os.path.abspath(__file__))
project_dir = os.path.dirnamd(file_handling_dir)
def ref(path):
path = path.lstrip('/\\') # remove any leading slashes
path = path.replace('\\', '/') # windows backslash to forward slashes, as windows supports both
return os.path.join(project_dir, path)
(the code above is untested)
then you do:
from File_Handling.Utils import ref
playerR = pygame.transform.scale(pygame.image.load(ref("Assets/Player_R.png"), "PlayerR"),
(PLAYER_WIDTH, PLAYER_HEIGHT))
``` instead of os.path.join.
I wouldn' worry about the slashes too much, as long as you only use forward slashes.
because you need to add it yourself
it only removed the files from your git history, so you need to commit the removal
oh, ok
(and add those two entries to .gitignore)
could you possibly explain what the ref function does
btw, Thank you soooooooooo much for helping me so far!
you could even remove them
the lstrip is just in case someone accidentally writes:
ref("/Assets/Player_R.png")
with a leading slash. that gets converted to "Assets/Player_R.png" (left strip \ and /, is what lstrip does)
the first block of code is giving me this warning:
Cannot find reference 'dirnamd' in 'path. pyi'
oh, ok
you should be able to fix that youself 😄
yeah, obviously
😄
ok, the ref function works for me, but I need someone else to test it on Windows
do I still need script_dir or can I leave that?
ok
and it should work from any location, without any extra ".." in there 🙂
(because it's resolve from the Utils.py file)
You said use "\" right? not "/"
ok
backslashes are windows
so use / (forward slashes) everywhere
windows can use them as well
that's a forward slash? Oh, LOL, I had no clue
well, \ is a backslash.
usually you call / just a slash, unless you want to explicitly separate it from backslashes... so you call it forward slash 🙂
I don't need import logging anymore, right?
ok, but can I replace ```py
logger.exception('some extra message here')withpy
error = "Sound Effects"
running = False
draw_except(error)```
yes. or at least add it before
it's up to you what you do with the error afterwards, as long as you never hide any error
ok, then what is the need ```py
script_dir = os.path.dirname(os.path.abspath(file))
logfile = ref(script_dir, 'mylog.log')
logging.basicConfig(filename=logfile, level=logging.INFO)```
of that
well, you don't need script_dir there
ref does that all for you
ref is supposed to replace all your os.path.join and any local "script_dir" variable, as it's all centralized
so will the logger make a logging file on the tester's computer, and I will have to ask them to share it for troubleshooting, right?
yes
ok
Thanks, I just need someone to test it for me once I commit the changes
would this work?
title_screen_music_check = os.path.exists(ref("Sounds/Background_music/Title_screen/Title_screen_music.mp3"))```
yes
ref just returns a full path to a file. you can always do:
print(ref("Sounds/....music.mp3"))
``` to see what you get (should output a full system path)
and because it's based in __file__, it should always adjust to the users current system. 🙂
no, like already said, you add those two lines to any file you need logging in
ok, I will add it to the files
right. and just so you know. logger.exception is only for exceptions. there are other logger functions like logger.debug, .info, .warning, .error
in that order. and depending on the loglevel in your basicConfig, only log messages of that configured level or higher will be logged.
willl py logging.getLogger() be the same as py from logging import getLogger()
no
ok
from logging import getLogger
logger = getLogger(__name__)
that is what you need. Exactly like that.
the __name__ is important, as it adds the module name where the logging happened (otherwise you'd search forever)
nah, not needed 🙂
ok
I'm here for helping, not for credit 🙂

is there anything I can do to repay you?
I really appreciate the time and effort you've given me
no, don't worry about stuff like that. 🙂
:white_check_mark: Your 3.12 eval job has completed with return code 0.
thank you!
uhh, I tried to commit and push, I got this error py error: Your local changes to the following files would be overwritten by merge: Drawing/Exception_Handling/__pycache__/draw_exception.cpython-312.pyc Drawing/Pause_Menu/__pycache__/pause_function.cpython-312.pyc Drawing/Title_screen/__pycache__/draw_title_screen.cpython-312.pyc Drawing/Tutorial_and_Information/__pycache__/Keybindings.cpython-312.pyc Drawing/Tutorial_and_Information/__pycache__/Welcome.cpython-312.pyc Drawing/__pycache__/draw.cpython-312.pyc File_Handling/__pycache__/Saving.cpython-312.pyc Pause_Menu/__pycache__/pause_function.cpython-312.pyc Sounds/Background_music/.DS_Store Title_screen/__pycache__/draw_title_screen.cpython-312.pyc Tutorial_and_Information/__pycache__/Information.cpython-312.pyc Merge with strategy ort failed.
uh
you may not have committed some stuff
did you add your stuff to .gitignore?
After adding the following to gitignore:
.idea/
__pycache__/
*.py[cod]
.DS_Store
try to run in this order:
git add .gitignore
git rm -rf --cached .DS_Store .idea *.py[cod]
git add .
git commit -m 'your commit message'
The commit went through, the push failed
I mean sometimes default in gitignore
well yea, depends on the tool that creates it.
You should really be using importlib.resources.files
what's that?
I can't pull either, cuz i get this error:
error: Your local changes to the following files would be overwritten by merge:
Drawing/Exception_Handling/pycache/draw_exception.cpython-312.pyc Drawing/Pause_Menu/pycache/pause_function.cpython-312.pyc Drawing/Title_screen/pycache/draw_title_screen.cpython-312.pyc Drawing/Tutorial_and_Information/pycache/Keybindings.cpython-312.pyc Drawing/Tutorial_and_Information/pycache/Welcome.cpython-312.pyc Drawing/pycache/draw.cpython-312.pyc File_Handling/pycache/Saving.cpython-312.pyc Pause_Menu/pycache/pause_function.cpython-312.pyc Sounds/Background_music/.DS_Store Title_screen/pycache/draw_title_screen.cpython-312.pyc Tutorial_and_Information/pycache/Information.cpython-312.pyc
Merge with strategy ort failed.
You need to gitignore your pyc files
You can add all this to your git ignore:
https://github.com/github/gitignore/blob/main/Python.gitignore
I have:
/File_Handling/highscore.pickle
mylog.log
Drawing/__pycache__/draw.cpython-312.pyc
Drawing/Tutorial_and_Information/__pycache__/Welcome.cpython-312.pyc
Drawing/Tutorial_and_Information/__pycache__/Keybindings.cpython-312.pyc
Drawing/Title_screen/__pycache__/draw_title_screen.cpython-312.pyc
Drawing/Pause_Menu/pause_function.py
Drawing/Pause_Menu/__pycache__/pause_function.cpython-312.pyc```
Those are the files in git.ignore
Remember to use code blocks for program output
it says
On branch main
Your branch and 'origin/main' have diverged,
and have 1 and 1 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
renamed: Exception_Handling/__pycache__/draw_exception.cpython-312.pyc -> Drawing/Exception_Handling/__pycache__/draw_exception.cpython-312.pyc
new file: Drawing/Pause_Menu/__pycache__/pause_function.cpython-312.pyc
new file: Drawing/Title_screen/__pycache__/draw_title_screen.cpython-312.pyc
new file: Drawing/Tutorial_and_Information/__pycache__/Keybindings.cpython-312.pyc
new file: Drawing/Tutorial_and_Information/__pycache__/Welcome.cpython-312.pyc
modified: Drawing/__pycache__/draw.cpython-312.pyc
modified: File_Handling/__pycache__/Saving.cpython-312.pyc
deleted: Pause_Menu/__pycache__/pause_function.cpython-312.pyc
renamed: .DS_Store -> Sounds/Background_music/.DS_Store
deleted: Title_screen/__pycache__/draw_title_screen.cpython-312.pyc
deleted: Tutorial_and_Information/__pycache__/Information.cpython-312.pyc
Untracked files:
(use "git add <file>..." to include in what will be committed)
.DS_Store
.idea/
File_Handling/__pycache__/Utility.cpython-312.pyc```
^
oh sorry
^
This is what it says in gitignore
If your code is too long to fit in a codeblock in Discord, you can paste your code here:
https://paste.pythondiscord.com/
After pasting your code, save it by clicking the Paste! button in the bottom left, or by pressing CTRL + S. After doing that, you will be navigated to the new paste's page. Copy the URL and post it here so others can see it.
that's what's in the git.ignore file
Use the official GitHub python gitignore
What do you mean?
how do i use that?
Paste it into your .gitignore
the whole file?
Yeah
ok
And use git restore --staged on your pyc files as git status recommended
I used this instead
https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
On branch main
Your branch and 'origin/main' have diverged,
and have 1 and 1 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: Drawing/__pycache__/draw.cpython-312.pyc
deleted: Exception_Handling/__pycache__/draw_exception.cpython-312.pyc
modified: File_Handling/__pycache__/Saving.cpython-312.pyc
deleted: Pause_Menu/__pycache__/pause_function.cpython-312.pyc
deleted: Title_screen/__pycache__/draw_title_screen.cpython-312.pyc
deleted: Tutorial_and_Information/__pycache__/Information.cpython-312.pyc
Untracked files:
(use "git add <file>..." to include in what will be committed)
.idea/
Drawing/Exception_Handling/__pycache__/
File_Handling/__pycache__/Utility.cpython-312.pyc
Sounds/Background_music/.DS_Store
no changes added to commit (use "git add" and/or "git commit -a")
I can't pull or push, I need help with that
You need to clean up your staged files first
Use git restore --staged for your modified pyc files
It also looks like your .gitignore hasn't been updated?
Did you amend a commit?
No...
Where's your .gitignore?
on github?
I just pushed all my changes to github
!paste
If your code is too long to fit in a codeblock in Discord, you can paste your code here:
https://paste.pythondiscord.com/
After pasting your code, save it by clicking the Paste! button in the bottom left, or by pressing CTRL + S. After doing that, you will be navigated to the new paste's page. Copy the URL and post it here so others can see it.
No you haven't, because you can't push right now
And I can see that your .gitignore doesn't have the JetBrains or Python gitignore content
I just did push it as a new commit so it should've updated
Show what you ran and the output
the output of the push?
Yes
11:50:26.807: [Space Dodge] git -c credential.helper= -c core.quotepath=false -c log.showSignature=false push --progress --porcelain origin refs/heads/main:main
Enumerating objects: 5, done.
Counting objects: 20% (1/5)
Counting objects: 40% (2/5)
Counting objects: 60% (3/5)
Counting objects: 80% (4/5)
Counting objects: 100% (5/5)
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads
Compressing objects: 33% (1/3)
Compressing objects: 66% (2/3)
Compressing objects: 100% (3/3)
Compressing objects: 100% (3/3), done.
Writing objects: 33% (1/3)
Writing objects: 66% (2/3)
Writing objects: 100% (3/3)
Writing objects: 100% (3/3), 2.40 KiB | 2.40 MiB/s, done.
Total 3 (delta 1), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 0% (0/1)
remote: Resolving deltas: 100% (1/1)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
remote: This repository moved. Please use the new location:
remote: https://github.com/Spacexplorer11/Space_Dodge.git
To https://github.com/TNTISGOOD/Space_Dodge.git
refs/heads/main:refs/heads/main baeb0bb..9a4296c
Done
Oh it looks like you got git pull working
Ok now delete all your __pycache__ and pyc and .DS_store files from your repo
You could build something with find and xargs
But it's probably best to do it manually
ok
Also it's a good idea to put all your python code into one package
Eg move your Main.py to space_doge/__main__.py and move your Assets and File_Handling to space_doge/assets and space_dodge/file_handling/ and run with python -m space_dodge
What do you mean, in one package? If possible, please open a pull request, it would help a lot in explaining and make it simpler
Currently you have a whole bunch of top level packages, and they all have mixed case
What are packages?
A directory of python code
Like this is a package https://github.com/Spacexplorer11/Space_Dodge/tree/main/File_Handling
But it's badly named and badly located
All the python code and assets for your project should sit inside one main package
how is "file_handling" a package, it's a directory?
You see all these dots in your imports: https://github.com/Spacexplorer11/Space_Dodge/blob/main/Main.py#L13
Main.py line 13
from Drawing.Exception_Handling.draw_exception import draw_except```
That shows you're using Drawing and Drawing.Exception_Handling as a package
oh
It should say from space_dodge.drawing.exception_handling import draw_except instead
But you need to move and rename your directories to do that
can you not open a pull request, because I don't understand how to do that
I'm on my phone so I can't do it
mkdir a space_dodge directory
And move Main.py into space_dodge/__main__.py
Then move all your Assets and other packages into space_dodge renaming to lowercase
Then run your code with python -m space_dodge
You'll see that you'll need to fix up your imports
so, make a directory called "Space_Dodge" inside Space_Dodge
then move main.py inside it?
No space_dodge
No
__main__.py is a file
You should look more carefully at the position and casing of letters when programming. They're all important
name my main.py to __main__.py
I really don't understand, could you maybe open a pull request later?
mkdir space_dodge
git mv Main.py space_dodge/__main__.py
Now move your Assets and other python directories into space_dodge
Making them lowercase as you do
And Sounds
so I need to rename all my files to lowercase and move them inside "space_dodge"
but why?
I don't need to move my LICENSE and gitignore right?
pep-8
No they stay at the root
oh, ok
ok
it's really just a matter of code style. I wouldn't bother for your current project, but keep it in mind for future projects
generally pep8 says: filenames, function names and variable names all use snake_case format. Only class names use CamelCase (without any underscores).
There are also some other things in pep-8, but those are the most prominent ones.
ok, I'll rename everything anyway
thank you so much!
I'm closing this post now
Thank you all sooooo much for your help!

!close
This help channel has been closed and it's no longer possible to send messages here. If your question wasn't answered, feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.