__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 -> '.'

With a trailing slash, dirname() treats reports/ as a folder with an empty file name and gives back reports itself. Path.parent ignores the slash and goes up to data.
For a bare file name, dirname() returns an empty string while Path.parent returns '.', the current folder. Code that checks if folder: behaves differently depending on which one you used.
Get the file name, stem and extension from a path
The last part of a path splits up the same way:
from pathlib import Path
report = Path("C:/data/reports/2026/sales.tar.gz")
print("name: ", report.name)
print("stem: ", report.stem)
print("suffix: ", report.suffix)
print("suffixes: ", report.suffixes)
print("renamed: ", report.with_name("costs.csv"))
Output:
name: sales.tar.gz
stem: sales.tar
suffix: .gz
suffixes: ['.tar', '.gz']
renamed: C:\data\reports\2026\costs.csv
.suffix is only the last extension, so sales.tar.gz gives .gz and a stem of sales.tar. .suffixes lists them all.
Get the current script’s name
For the name of the running script itself, __file__ beats sys.argv[0]:
import sys
from pathlib import Path
print("sys.argv[0]: ", sys.argv[0])
print("__file__: ", __file__)
print("Path(__file__).name: ", Path(__file__).name)
print("Path(__file__).stem: ", Path(__file__).stem)
Output:
sys.argv[0]: tools\export_report.py
__file__: C:\pyguides\runs\curfile\tools\export_report.py
Path(__file__).name: export_report.py
Path(__file__).stem: export_report
sys.argv[0] is exactly what was typed on the command line, tools\export_report.py here. __file__ is the full path, so .name and .stem give a clean name either way.
.with_name() swaps the file name and keeps the folder. There’s more on this in getting a file name from a path and getting a file extension.
Get the path of an imported module with __file__
__file__ isn’t only for the script you run. Every imported module has one, pointing at its own file:
from pathlib import Path
import helpers.tools as tools # helpers/tools.py sets HERE = Path(__file__).resolve().parent
print("tools module:", tools.__file__)
print("tools.HERE: ", tools.HERE)
Output:
tools module: C:\pyguides\runs\curfile\helpers\tools.py
tools.HERE: C:\pyguides\runs\curfile\helpers
The helper module computed HERE from its own __file__, so it knows its folder regardless of who imported it. This is how packages find the data files that ship with them.
The import worked without any path tweaking because Python puts the script’s folder first on sys.path. Importing a file from the same directory covers the rules.
Why os.path.dirname(__file__) returned an empty string
You’ll still see warnings that os.path.dirname(__file__) can come back empty. I ran the same script on Python 3.8 and on current Python:
import os, sys
print(sys.version.split()[0], "| __file__:", repr(__file__), "| dirname:", repr(os.path.dirname(__file__)))
Output:
3.8.10 | __file__: 'where_version.py' | dirname: ''
3.14.7 | __file__: 'C:\\pyguides\\runs\\curfile\\where_version.py' | dirname: 'C:\\pyguides\\runs\\curfile'

__file__ was just the name you typed, so its folder was an empty string.On 3.8, __file__ was exactly what you typed, so where_version.py had no folder part and dirname() returned an empty string. I also checked 3.9, which already gives the full path.
So the warning only applies to Python 3.8 and older. Wrapping it in os.path.abspath() or using Path(__file__).resolve() is still a good habit, and it’s harmless on new versions.
One place __file__ never exists is the interactive prompt, or code run with python -c. There you’ll get NameError: name '__file__' is not defined.
Python file path quick reference: pathlib and os.path
Here’s every task from this article in one place, with both styles side by side:
| Task | pathlib | os.path |
|---|---|---|
| Path of the current file | Path(__file__).resolve() | os.path.abspath(__file__) |
| Folder of the current file | Path(__file__).resolve().parent | os.path.dirname(os.path.abspath(__file__)) |
| Two folders up | .parents[1] | dirname(dirname(...)) |
| Absolute path of a name | Path(name).resolve() | os.path.abspath(name) |
| Folder of any path | Path(p).parent | os.path.dirname(p) |
| File name | Path(p).name | os.path.basename(p) |
| Name without extension | Path(p).stem | os.path.splitext(os.path.basename(p))[0] |
| Join a folder and a name | folder / "data.csv" | os.path.join(folder, "data.csv") |
The pathlib column is shorter in almost every row, which is the practical reason to prefer it. Remember the two rows where they disagree: trailing slashes and bare file names.
On a Mac or Linux machine every path in this article looks like /Users/ava/projects/reports/tools/report.py, with forward slashes. The methods and their results work the same way.
These file and folder guides fit well alongside this one:
- Check if a directory exists in Python
- Read a file line by line
- List files in a directory
- Get the current working directory
Frequently asked questions
How do I get the path of the current file in Python?
Use __file__. Path(__file__).resolve() gives the full, resolved path of the running script or module.
How do I get the directory of the current script?
Use Path(__file__).resolve().parent, or os.path.dirname(os.path.abspath(__file__)) with the os module.
What does Path(__file__).resolve().parent do?
It takes the current file’s path, resolves it to a real absolute path, and returns the folder that contains it.
How do I get the directory from any file path?
Use Path(path).parent or os.path.dirname(path). They differ for a trailing slash and a bare file name.
Why is os.path.dirname(__file__) empty?
On Python 3.8 and older, __file__ was the relative name you typed, so it had no folder part. Python 3.9 and later make it absolute.
Why do I get NameError: name ‘__file__’ is not defined?
__file__ only exists in a file that Python is running or importing. The interactive prompt and python -c don’t set it.
Should I use os.path or pathlib?
Either works. pathlib reads more cleanly and is the modern choice; the Python pathlib documentation has a table mapping each os.path function to its pathlib equivalent.

Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn