os.path.join for getting up level paths
Question:
Consider you have the following code:
os.path.abspath(os.path.join('../../', __file__))
I am quite puzzled because currently, it is returning me the same path such in __file__
path.
Any idea why I don’t get two levels up of the __file__
path?
Answers:
From the documentation (emphasis mine):
os.path.join(path, *paths)
Join one or more path components
intelligently. The return value is the concatenation of path and any
members of *paths with exactly one directory separator (os.sep)
following each non-empty part except the last, meaning that the result
will only end in a separator if the last part is empty. If a component
is an absolute path, all previous components are thrown away and
joining continues from the absolute path component.
__file__
is an absolute path, so join
ignores the preceding ../../
.
__file__
is an absolute file path and so the join attempts something like the following:
os.path.join('../../', '/path/to/file')
Since the second argument is already an absolute path, all previous ones are ineffective.
Also note that __file__
contains the file name itself so if you want to go two directories up you’d need to split that off. The easiest solution is to use pathlib.Path
:
Path(__file__).parents[2]
If you want to go n
levels up you can use Path(__file__).parents[n]
.
After some more trial and error I think I found the best solution:
os.path.abspath(os.path.join(__file__, '../../'))
This worked for me. A few years later. Looks to me like abspath will make sure ../ work as it should in a path instead of just a normal string. Absolute genius.
Consider you have the following code:
os.path.abspath(os.path.join('../../', __file__))
I am quite puzzled because currently, it is returning me the same path such in __file__
path.
Any idea why I don’t get two levels up of the __file__
path?
From the documentation (emphasis mine):
os.path.join(path, *paths)
Join one or more path components
intelligently. The return value is the concatenation of path and any
members of *paths with exactly one directory separator (os.sep)
following each non-empty part except the last, meaning that the result
will only end in a separator if the last part is empty. If a component
is an absolute path, all previous components are thrown away and
joining continues from the absolute path component.
__file__
is an absolute path, so join
ignores the preceding ../../
.
__file__
is an absolute file path and so the join attempts something like the following:
os.path.join('../../', '/path/to/file')
Since the second argument is already an absolute path, all previous ones are ineffective.
Also note that __file__
contains the file name itself so if you want to go two directories up you’d need to split that off. The easiest solution is to use pathlib.Path
:
Path(__file__).parents[2]
If you want to go n
levels up you can use Path(__file__).parents[n]
.
After some more trial and error I think I found the best solution:
os.path.abspath(os.path.join(__file__, '../../'))
This worked for me. A few years later. Looks to me like abspath will make sure ../ work as it should in a path instead of just a normal string. Absolute genius.