I don't do as much Python as I used to do. The few projects I still maintain, in Python, have a pyproject.toml and uv.lock. I.e. I'm using uv for getting the right executable version of Python and for installing dependencies. No more pip install ... and no more requirements.(in|txt). And definitely no poetry.lock.

And pyenv stopped working entirely when Python 3.12 came out. I used to use pyenv instead of Homebrew to get different versions of Python for different projects. uv is just that much better. I still use virtual envs, in the form of uv sync && source .venv/bin/activate when working inside a project and want to be able to type python ... and that referring to the exact version of Python with the relevant dependencies (from the pyproject.toml) installed.

However, there's a problem how: Outside of projects (that have a pyproject.toml and uv.lock) I no longer have a valid python executable. There's still a python3 executable that comes from /opt/homebrew/bin/python3 but that one I can't add dependencies to.
And many times I just want to whip up a quick script or start a repl, but with some certain dependencies installed. For example, to run...


import requests
print(requests.get('https://www.peterbe.com').headers['content-type'])
# prints 'text/html; charset=utf-8'

Again, uv to the rescue! I created ~/bin/python (plus chmod +x ~/bin/python) which now looks like this:


#!/bin/bash
set -x
uv run --python 3.12 --with requests python $@

Now I can quickly start a repl. Or if I create a /tmp/test-something.py I can just run that with


python /tmp/test-something.py

The reason for the set -x in that Bash script is simply to remind me that this starting of python is this Bash script that uses uv run ....

The --with requests is admittedly a bit arbitrary. It's only sometimes that a quick Python session needs the requests package. Sometimes that'd be a waste and sometimes I might need some other package. But that's why the set -x above is a good reminder how this works. So, if I need some other package, I can just remind myself how this works. For example:

cat /tmp/test-something.py
import cowsay

cowsay.cow('Hello World')

❯ uv run --python 3.12 --with cowsay python /tmp/test-something.py
Installed 1 package in 19ms
  ___________
| Hello World |
  ===========
           \
            \
              ^__^
              (oo)\_______
              (__)\       )\/\
                  ||----w |
                  ||     ||

Comments

Your email will never ever be published.

Previous:
My 2024 golf goals December 30, 2024 Golf
Next:
TypeScript enums without enums January 29, 2025 JavaScript, TypeScript
Related by category:
How to resolve a git conflict in poetry.lock February 7, 2020 Python
get in JavaScript is the same as property in Python February 13, 2025 Python
Best practice with retries with requests April 19, 2017 Python
How to avoid a count query in Django if you can February 14, 2024 Python
Related by keyword:
Best practice with retries with requests April 19, 2017 Python
Cope with JSONDecodeError in requests.get().json() in Python 2 and 3 November 16, 2016 Python
Fastest way to download a file from S3 March 29, 2017 Python
How to close a HTTP GET request in Python before the end March 30, 2022 Python