Recently like a lot of my Python follows, I have been using uv to manage a lot of my python projects.
Given a project, uv tree
will show you a nice tree view of your requirements.
wheat v0.1.0
├── click v8.1.8
├── inquirer v3.4.0
│ ├── blessed v1.20.0
│ │ ├── six v1.17.0
│ │ └── wcwidth v0.2.13
│ ├── editor v1.6.6
│ │ ├── runs v1.2.2
│ │ │ └── xmod v1.8.1
│ │ └── xmod v1.8.1
│ └── readchar v4.2.1
└── tomlkit v0.13.2
You can also do something like uv pip list
to show it in list form.
Both support a --outdated
flag to show you packages needing updates.
uv pip list --outdated
Package Version Latest Type Editable project location
------- ------- ------ ----- ---------------------------------
wheat 0.1.0 0.9.5 wheel ~/Projects/wheat
The pip list
command also supports a --format=json
command to give us a json version we can work with.
I’ve used peco in the CLI multiple times to make selecting from a list easier, so I was curious to do that with Python package lists.
I decided to add a command to my wheat
package tool (name inspired by rye
) that I use to wrap some common development tasks for my personal environment.
@click.command("list")
@click.option("--outdated", is_flag=True)
def list_packages(outdated):
def packages():
args = ["uv", "pip", "list", "--format=json"]
if outdated:
args.append("--outdated")
output = util.check_output(*args)
for pkg in json.loads(output):
if outdated:
yield f"{pkg['name']} {pkg['version']} -> ({pkg['latest_version']})", pkg["name"]
else:
yield f"{pkg['name']} {pkg['version']}", pkg["name"]
question = inquirer.List("package", "Select package", choices=list(packages()))
try:
selection = inquirer.prompt(questions=[question], raise_keyboard_interrupt=True)
except KeyboardInterrupt:
return
else:
webbrowser.open(f"https://pypi.org/project/{selection['package']}/")
Given this, we can run our command and get a selectable list that will automatically bring us to the package on PyPi.
wheat list --outdated
[?] Select package:
amqp 5.2.0 -> (5.3.1)
billiard 4.2.0 -> (4.2.1)
certifi 2024.8.30 -> (2024.12.14)
click 8.1.7 -> (8.1.8)
> django 4.2.16 -> (5.1.5)
django-cors-headers 3.10.1 -> (4.6.0)
django-debug-toolbar 4.4.6 -> (5.0.1)
django-environ 0.9.0 -> (0.12.0)
django-filter 2.4.0 -> (24.3)
django-include-bootstrap 4.0.0 -> (5.0.0)
fluent-logger 0.10.0 -> (0.11.1)
importlib-metadata 4.8.3 -> (8.5.0)
keyring 23.4.1 -> (25.6.0)
This is just a quick draft, but something that I have often thought would be useful when checking my project for updates or other projects to understand their dependencies. I think I would like to find something other than inquirer that has a few less requirements, but this was enough for me to at least test my idea to see how it works.