__file__ holds the path of the current Python file, so getting the path of the current file in Python is a one-liner. Wrap it in pathlib for the folder too:
from pathlib import Path
this_file = Path(__file__).resolve()
this_folder = this_file.parent
I’ll also show how to get the directory of any file path, and the edge cases where the two common methods disagree. All output is from Python 3.14.7 on Windows.

Get the path of the current file in Python with __file__
Every script and module gets a __file__ variable holding its own path. Here it is with pathlib:
from pathlib import Path
this_file = Path(__file__)
print("this file: ", this_file)
print("its folder: ", this_file.parent)
print("file name: ", this_file.name)
print("without .py: ", this_file.stem)
Output:
this file: C:\pyguides\runs\curfile\file_path.py
its folder: C:\pyguides\runs\curfile
file name: file_path.py
without .py: file_path

Path(__file__) gives the full path, and .parent, .name and .stem split it up.On current Python, __file__ is already a full, absolute path when you run a script, even if you typed a relative one. That wasn’t always true, as the last section shows.
.parent is the folder, .name is the file name, and .stem drops the extension. That’s usually all you need.
Get the directory of the current file (the script’s folder)
Path(__file__).resolve().parent is the line to remember. It’s the folder the script lives in, which is not the same as the working directory you ran it from.
If you’re unsure which one you need, getting the current working directory explains the difference with a real example.
It’s also the phrase people search for most on this topic, and it’s worth knowing why the .resolve() is there. That’s two sections down.
Without .resolve(), Path(__file__).parent usually gives the same folder, because __file__ is already absolute on current Python. The two only differ when the path runs through a short name or a link.
The os.path equivalent is os.path.dirname(os.path.abspath(__file__)). It’s longer, but you’ll meet it constantly in older projects, so it’s worth recognizing.
Go up to the project root with .parents
Scripts often live a few folders deep, while the data sits at the project root. .parents walks up as far as you need:
from pathlib import Path
HERE = Path(__file__).resolve().parent
PROJECT = HERE.parents[1] # src/app -> src -> project
print("this file's folder:", HERE)
print("one level up: ", HERE.parent)
print("project root: ", PROJECT)
print("data file: ", PROJECT / "data" / "sales.csv")
Output:
this file's folder: C:\pyguides\runs\curfile\src\app
one level up: C:\pyguides\runs\curfile\src
project root: C:\pyguides\runs\curfile
data file: C:\pyguides\runs\curfile\data\sales.csv
HERE.parents[1] is two levels above the script’s folder, which is the project root in a src/app layout. Building every data path from that one constant keeps a whole project portable.
I prefer naming it once, like PROJECT, over repeating .parent.parent in several files. When the layout changes, there’s one line to fix.
Get the path of the current file with os.path
Older code does the same thing with os.path, working on plain strings:
import os
print("__file__: ", __file__)
print("os.path.abspath(): ", os.path.abspath(__file__))
print("os.path.dirname(): ", os.path.dirname(os.path.abspath(__file__)))
print("os.path.basename(): ", os.path.basename(__file__))
Output:
__file__: C:\pyguides\runs\curfile\ex_osway.py
os.path.abspath(): C:\pyguides\runs\curfile\ex_osway.py
os.path.dirname(): C:\pyguides\runs\curfile
os.path.basename(): ex_osway.py
os.path.abspath() makes the path absolute, os.path.dirname() strips the file name, and os.path.basename() keeps only the file name.
Both approaches give the same folder here. I use pathlib in new code because the pieces are attributes instead of nested function calls.
Read a file next to the script, from any folder
This is why most people want the script’s folder. Here the script is in a tools folder and gets launched from the folder above it:
import os
from pathlib import Path
HERE = Path(__file__).resolve().parent
settings = HERE / "settings.ini"
print("running from: ", Path.cwd())
print("script folder:", HERE)
print("settings.ini next to the script exists? ", settings.exists())
print("settings.ini in the working folder exists?", os.path.exists("settings.ini"))
Output:
running from: C:\pyguides\runs\curfile
script folder: C:\pyguides\runs\curfile\tools
settings.ini next to the script exists? True
settings.ini in the working folder exists? False

settings.ini works no matter where you launch the script.settings.ini sits next to the script, so the path built from HERE finds it. A bare "settings.ini" would look in the working directory and miss it.
Before opening anything, checking that the file exists gives you a friendlier error than a traceback.
Why use Path(__file__).resolve()?
On Windows, a path can reach your script through a short “8.3” folder name. .resolve() turns it into the real one:
from pathlib import Path
print("__file__: ", __file__)
print("Path(__file__): ", Path(__file__))
print(".resolve(): ", Path(__file__).resolve())
print(".resolve().parent: ", Path(__file__).resolve().parent.name)
Output:
__file__: C:\pyguides\runs\curfile\SALESR~1\where.py
Path(__file__): C:\pyguides\runs\curfile\SALESR~1\where.py
.resolve(): C:\pyguides\runs\curfile\SalesReports2026\where.py
.resolve().parent: SalesReports2026

__file__ keeps it; .resolve() gives the real folder name.I launched the script through the folder’s short name, SALESR~1, which Windows still generates for long names. __file__ kept it, while .resolve() gave back SalesReports2026.
On macOS and Linux, .resolve() mainly matters for symbolic links, which it follows to the real file. Either way, resolving first means two paths to the same file compare as equal.
One thing .resolve() isn’t needed for any more is removing ... Current Python already cleans that out of __file__.
Get the absolute path of a file in Python
For a file name rather than the running script, turn it into a full path with os.path.abspath() or pathlib:
import os
from pathlib import Path
name = "sales.csv"
print("os.path.abspath(): ", os.path.abspath(name))
print("Path().resolve(): ", Path(name).resolve())
print("Path().absolute(): ", Path(name).absolute())
print("does it exist? ", Path(name).exists())
Output:
os.path.abspath(): C:\pyguides\runs\curfile\sales.csv
Path().resolve(): C:\pyguides\runs\curfile\sales.csv
Path().absolute(): C:\pyguides\runs\curfile\sales.csv
does it exist? False
All three glue the name onto the current working directory. They don’t look at the disk, which is why the last line says the file doesn’t exist even though a full path came back.
.resolve() also cleans up .. and follows links, while .absolute() only adds the directory. If you need to know the file is really there, check .exists() separately.
That’s the most common surprise with “get the file path” code. A perfectly valid-looking path proves nothing until you check it.
Get the directory of any file path in Python
For a path that isn’t the current script, like one you read from a config or an argument, the same tools apply:
import os
from pathlib import Path
path = "C:/data/reports/2026/sales.csv"
print("os.path.dirname(): ", os.path.dirname(path))
print("Path().parent: ", Path(path).parent)
print("two levels up: ", Path(path).parents[1])
print("os.path.split(): ", os.path.split(path))
Output:
os.path.dirname(): C:/data/reports/2026
Path().parent: C:\data\reports\2026
two levels up: C:\data\reports
os.path.split(): ('C:/data/reports/2026', 'sales.csv')
os.path.dirname() and Path().parent both strip the last part. .parents[1] goes two levels up, and os.path.split() gives you folder and file name together.
To list what’s inside a folder once you have it, see listing files in a directory with Python.
Where os.path.dirname() and Path.parent disagree
They look interchangeable, and for a normal file path they are. Two cases catch people out:
import os
from pathlib import Path
for path in ("C:/data/reports/sales.csv", "C:/data/reports/", "sales.csv"):
print(f"{path!r:<28} dirname -> {os.path.dirname(path)!r:<20} Path.parent -> {str(Path(path).parent)!r}")
Output:
'C:/data/reports/sales.csv' dirname -> 'C:/data/reports' Path.parent -> 'C:\\data\\reports'
'C:/data/reports/' dirname -> 'C:/data/reports' Path.parent -> 'C:\\data'
'sales.csv' dirname -> '' Path.parent -> '.'