Python 3.14 is now officially released, and I'd like to share some of my favorite new features.
I'm not going to talk about the experimental free-threading mode, the just-in-time compiler, or other performance improvements. I'm going to focus on features that you can use right after you upgrade.
One of the most immediately visible features in Python 3.14 is all the color!
The Python REPL now includes syntax highlighting:
When you type code into the Python REPL, it will be colorized as you type it.
The Python debugger also gains syntax highlighting in 3.14:
So when you're debugging code, whether with a breakpoint call or some other way of entering PDB, your source code will now be colorized.
Also, if you've ever wished that Python's unittest module included nicely colored output like pytest, it does now.
Now with unittest, failing tests are red and passing tests are green:
And that's not all the color!
The argparse module now also supports colorized help text:
The calendar module now highlights the current date when you print a calendar.
Also, the json module's command line interface now displays JSON output in color by default:
Speaking of the json module's command-line interface, you can now run it with python-m json instead of python-m json.tool:
$ echo '[{"id": 100, "name": "Trey", "is_admin": true}]' | python -m json
[
{
"id": 100,
"name": "Trey",
"is_admin": true
}
]
I actually made this tiny change, and it's the first code contribution I've made to Python. It is a very small one, but kind of a neat one.
Python 3.14 includes even more improvements to error messages, particularly syntax errors.
In previous versions of Python, you'd often get a generic SyntaxError if you misspelled a Python keyword like import:
>>> improt math
File "<stdin>", line 1
improt math
^^^^
SyntaxError: invalid syntax
But in Python 3.14, the error message now suggests the correct keyword instead:
>>> improt math
File "<python-input-6>", line 1
improt math
^^^^^^
SyntaxError: invalid syntax. Did you mean 'import'?
Python's error messages have improved a lot in the past few versions, and this is exactly the kind of change that makes Python even more beginner-friendly.
Another REPL improvement that I stumbled upon recently while teaching is tab completion of Python imports.
When you're in the REPL and you type the import statement followed by the start of a module name, and then you hit tab, it auto-completes the module name:
>>> import col<TAB>
collections colorsys
This is especially handy for long module names like collections or datetime.
Python 3.14 also includes a bunch of little improvements to various standard library modules.
For example, the argparse module now includes a suggest_on_error argument that will suggest corrections when you make a typo in the choices options for a command-line argument:
import argparse
objects = ["rock", "paper", "scissors"]
parser = argparse.ArgumentParser(suggest_on_error=True)
parser.add_argument("player1", choices=objects)
parser.add_argument("player2", choices=objects)
args = parser.parse_args()
if args.player1 == args.player2:
print("It's a tie.")
else:
index = objects.index(args.player1)
if args.player2 == objects[index-1]:
print("Player 1 wins")
else:
print("Player 2 wins")
Here we're misspelling scissors, and Python is showing us the option that it thinks we meant to type, spelled correctly:
$ python rock.py rock scisors
usage: rock.py [-h] {rock,paper,scissors} {rock,paper,scissors}
rock.py: error: argument player2: invalid choice: 'scisors', maybe you
meant 'scissors'? (choose from rock, paper, scissors)
pathlib has copy and move methods!One of my favorite features in Python 3.14 is that pathlib.Path objects now have copy and move methods.
Before 3.14, if we wanted to copy or move a file, we had to use Python's shutil module:
>>> from pathlib import Path
>>> import shutil
>>> source = Path("readme.txt")
>>> destination = Path("readme.md")
>>> shutil.move(source, destination)
PosixPath('readme.md')
But in 3.14, you can just use the move method directly on the Path object:
>>> from pathlib import Path
>>> source = Path("readme.txt")
>>> destination = Path("readme.md")
>>> source.move(destination)
PosixPath('readme.md')
There's also a move_into method for moving a file into a directory, as well as a copy method and a copy_into method.
info attribute for pathlib.PathThe Path class also gained a new info attribute that caches information about whether a path represents an existing file or directory:
>>> source.info.is_file()
True
>>> source.info.is_dir()
False
datetimeIn 3.14, you can also now parse a date string or a time string directly into a datetime.date object or a datetime.time object.
In previous versions of Python, you either needed to use datetime.datetime.strptime, and then extract the date or parse the string manually:
>>> from datetime import datetime
>>> date_string = "2026-03-14"
>>> datetime.strptime(date_string, "%Y-%m-%d").date()
datetime.date(2026, 3, 14)
But in 3.14, you can just use date.strptime directly.
The date and time classes now have their own strptime method that works the same way as the datetime class's strptime method:
>>> from datetime import date
>>> date_string = "2026-03-14"
>>> date.strptime(date_string, "%Y-%m-%d")
datetime.date(2026, 3, 14)
uuid7: UUIDs sortable by creation timePython's uuid module now includes uuid6, uuid7, and uuid8 functions.
If you're starting a new project and you need to generate UUIDs, I'd recommend taking a look at uuid7:
>>> from uuid import uuid7
>>> uuid7()
UUID('0199b0ac-022f-72fb-9350-af229cb89256')
>>> uuid7()
UUID('0199b0ac-10b0-7628-8c45-96ab90bcc870')
>>> uuid7()
UUID('0199b0ac-1847-75d5-b17a-298cc953ea99')
It has all the pseudo-randomness benefits of uuid4, but the generated UUIDs are also ordered by their creation time.
The sortability of these UUIDs can be really useful for things like database primary keys.
Have you ever written code that catches multiple exception types?
In previous Python versions, you needed to wrap those exception types in parentheses:
>>> value = "3"
>>> try:
... int(value)
... except (ValueError, TypeError):
... print("Invalid number")
...
3
In 3.14, you can omit the parentheses and the code still works:
>>> value = "3"
>>> try:
... int(value)
... except ValueError, TypeError:
... print("Invalid number")
...
3
This earlier version was a holdover back from the Python 2 days.
3.14 also includes some interesting improvements for concurrent and parallel programming.
concurrent.futures now includes an InterpreterPoolExecutor, which spawns a new Python interpreter in a separate thread, but in the same process:
>>> from concurrent.futures import InterpreterPoolExecutor
Each interpreter has its own global interpreter lock, meaning they can each use separate CPUs if needed.
So you kind of get the best of both worlds between multi-threading and multi-processing.
Also, if you've ever needed to inspect running asyncio tasks, well, you can now do so from the command-line.
$ python -m asyncio pstree PID
3.14 now also has an external debugger interface that allows you to safely attach debuggers to running Python processes, so you can start a breakpoint from a process that's already running.
$ python -m pdb --pid 49611
The last thing I'd like to talk about in 3.14 is a new syntax, t-strings:
>>> name = "World"
>>> template = t"Hello {name}"
The "T" in t-string stands for template.
Unlike f-strings, they don't actually make strings.
They make Template objects:
>>> template
Template(strings=('Hello ', ''), interpolations=(Interpolation('World', 'name', None, ''),))
These Template objects allow a utility to pre-process the interpolations within the template, in whatever way they'd like, before actually making a string.
Keep in mind that f-strings are still the go-to string formatting tool.
T-strings are really useful for library authors, in particular. So you might find yourself soon using a library in Python where a t-string is required and not an f-string, because some pre-processing needs to be done in some of your data.
You can find my video about t-strings here.
If you're excited about syntax highlighting, the new pathlib methods, or anything else that I mentioned, go install Python 3.14 and try it out.
And if you want to see everything that's new, go to the "What's New in Python 3.14" page in the documentation.
Need to fill-in gaps in your Python skills?
Sign up for my Python newsletter where I share one of my favorite Python tips every week.
Need to fill-in gaps in your Python skills? I send weekly emails designed to do just that.
Sign in to your Python Morsels account to track your progress.
Don't have an account yet? Sign up here.