blog Exploring Python Requirements

Tags:
python

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.