For the longest time, I have been frustrated with Python because I couldn’t use it for one-off scripts. I had to first ensure it was running in an environment where it could find the right Python version and the dependencies installed. That is now a thing of the past.
If you are not a Pythonista (or one possibly living under a rock), uv is an extremely fast Python package and project manager, written in Rust.
uv also provides this nifty tool called uvx (kinda like npx from the Node/NPM ecosystem for Javascript/Typescript packages) which can be used to invoke a Python tool inside a package. uvx takes care of creating a (cached) disposable virtual environment, setting up the right Python version and installing all the dependencies before running.
PEP 723 is a Python Enhancement Proposal that specifies a metadata format that can be embedded in single-file Python scripts to assist launchers, IDEs and other external tools which may need to interact with such scripts.
Here is the example directly lifted from the proposal:
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "requests<3",
# "rich",
# ]
# ///
import requests
from rich.pretty import pprint
resp = requests.get("https://peps.python.org/api/peps.json")
data = resp.json()
pprint([(k, v["title"]) for k, v in data.items()][:10])
Combining uv and the PEP-723 metadata inside a Python script, we can run the script in the previous section as follows:
$ uv run pep.py
Installed 9 packages in 24ms
[
│ ('1', 'PEP Purpose and Guidelines'),
│ ('2', 'Procedure for Adding New Modules'),
│ ('3', 'Guidelines for Handling Bug Reports'),
│ ('4', 'Deprecation of Standard Modules'),
│ ('5', 'Guidelines for Language Evolution'),
│ ('6', 'Bug Fix Releases'),
│ ('7', 'Style Guide for C Code'),
│ ('8', 'Style Guide for Python Code'),
│ ('9', 'Sample Plaintext PEP Template'),
│ ('10', 'Voting Guidelines')
]
We can combine things we covered in the previous sections to create a simple executable script that can extract YouTube transcripts.
First we create a Python script with a shebang and inline metadata.
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.8"
# dependencies = [
# "youtube-transcript-api",
# ]
# ///
import sys
import re
from youtube_transcript_api import YouTubeTranscriptApi
from youtube_transcript_api.formatters import TextFormatter
if len(sys.argv) < 2:
print('Usage: provide YouTube URL or video_id as argument', file=sys.stderr)
sys.exit(1)
url_or_id = sys.argv[1]
# Extract video ID from URL if it's a full URL
video_id_match = re.search(r'(?:v=|/)([a-zA-Z0-9_-]{11})', url_or_id)
if video_id_match:
video_id = video_id_match.group(1)
else:
# Assume it's already a video ID
video_id = url_or_id
try:
ytt_api = YouTubeTranscriptApi()
transcript = ytt_api.fetch(video_id)
formatter = TextFormatter()
print(formatter.format_transcript(transcript))
except Exception as e:
print(f'Error: {e}', file=sys.stderr)
sys.exit(1)
Note the shebang line: #!/usr/bin/env -S uv run --script. It is important to specify uv run with the --script flag when used on the shebang line.
We save this script as ytt and then make it executable with chmod +x ytt.
We can now run the script like:
$ ./ytt https://www.youtube.com/watch?v=zgSQr0d5EVg
Installed 7 packages in 10ms
hey it's Matt here and today I'm going
to show you how to use UV not only to
install packages in your python projects
but to manage entire projects to create
virtual environments and even how to
manage entire versions of python with UV
uh and hopefully you'll understand by
any of this video UV is a dropin
…<snipped text>…
Fun times
This opens up a lot of possibilities for running Python code more seamlessly. Before this I used to prefer Go for one-off scripts because it was easy to create a self-contained binary executable. But now that I could use uv, I coded up a quick MCP server in Python for extracting YouTube transcripts. Check it out on Github at cottongeeks/ytt-mcp.