Ryan Scott Brown

I build cloud-based systems for startups and enterprises. My background in operations gives me a unique focus on writing observable, reliable software and automating maintenance work.

I love learning and teaching about Amazon Web Services, automation tools such as Ansible, and the serverless ecosystem. I most often write code in Python, TypeScript, and Rust.

B.S. Applied Networking and Systems Administration, minor in Software Engineering from Rochester Institute of Technology.

    TIL: uv scripting and uvx

    I’ve known about Astral’s uv and uvx tools for a while, but over the holidays break I’ve been working to streamline my setup and (if possible) simplify the tools I use.

    Changing over to uv from pipx/pyenv/pipenv helps solve my accumulation of one-off scripts. Normally, when I write a script I make a new directory with a __main__.py, requirements.txt, the works. Now with uv I can keep all my one-offs in a single directory for reuse or reference while keeping dependencies reasonable.

    Every script starts something like this:

    #!/usr/bin/env uv run
    # /// script
    # requires-python = ">=3.13"
    # dependencies = [ "boto3" ]
    # ///
    
    import sys, boto3
    s3 = boto3.client('s3')
    
    if __name__ == "__main__":
        s3.list_objects_v2(Bucket=sys.argv[1])
    

    This takes advantage of in-script toml-ish metadata, a new-ish PEP that lets uv construct a temporary virtualenv matching your script’s needs when you invoke the script thanks to the #! line.

    If you dump the above into a file and chmod a+x it, then as long as uv is on your system you can reconstruct the deps and run the script independently of what your other scripts have needed in the meantime. There’s a built-in command uv init --script myscript.py that works, but doesn’t include the #! (shebang) line so you’ll want to add that.

    If you’d like to upgrade from a one-shot script to a command you’ll regularly use (and rename from mytool.py to mytool) the shebang needs to be updated to #!/usr/bin/env uv run --script --quiet. If you don’t include the --script flag it will recusively execute forever until you interrupt it.

    See the uv scripting docs for more details on how scripting and dependencies work. There’s also uvx, which lets you run existing tools the same way. I was teaching some basic Python in Marimo and it’s easy to spin up a new notebook with dependencies like:

    uvx --with quart marimo new
    

    That starts a new notebook server and installs quart, a unit conversion library.

    Design by Sam Lucidi (samlucidi.com)