Get a File's Name without Extensions in Python

June 2019

Too Many Dots

I feel like Python gaslights me every time I try to remove extensions from a filename. This does what I expect:

from pathlib import Path

name = Path("target_name.txt").stem
print(name)
Output:
target_name

Then, this happens:

from pathlib import Path

name = Path("target_name.tmp.txt").stem
print(name)
Output:
target_name.tmp

You see, .tmp is an extension. It should not be there. I've worked around this in various ways. None of them pretty. Today, I found an Elegant Solution

Just The Front

Thanks to a great answer1 on Stack Overflow, I've learned this approach that Just Works™:

from pathlib import Path

file_path = Path("/alfa/bravo.charlie/target_name.ext.tar.gz")
name = file_path.name.removesuffix("".join(file_path.suffixes))
print(name)
Output:
target_name

It handles everything I need2. Including files that start with a dot (e.g. .env). I checked everything I can think of in this post: Test Suite For: Getting a File's Name without Extensions in Python.

What's In A Name

It seems weird that there's not a built-in way to do this. Something like .stem that removes all the extensions. Maybe there will be one day. Until then, I've got this.

-a

end of line

Endnotes

The first version of this post was made in 2019. It's been edited a few times since then. My approach in the prior iteration looked like this:

import os

file_path = "target_name.tar.gz"
name = os.path.basename(file_path).split('.')[0]
print(name)
Output:
target_name

It works fine for most cases but falls down on files that start with a . character. The results come back empty. I knew that and could avoid it if there was going to be a problem. This new approach handles the leading . characters. No more worrying about the issue at all.

References

I was originally looking for this under the Path documentation. Path.name makes a string though. Hence, it's here.

Footnotes

All the other answers only remove one extension (e.g. target_name.tar.gz becomes target_name.tar instead of target_name). That's basically never what I want. This answer is the solution I've been looking for. As of the time of this writing the top answer (which leaves it at target.tar) has 1,909 upvote. This answer has 4. I added the test suite from this post to show how well it works. Hopefully, that'll get it some more love.

Head's up that using this approach on my mac doesn't handle Window file paths like:

C:\alfa\bravo\target_name.txt

I haven't tried to get them to work since I don't use them.