Skip to content

Commit

Permalink
feat: runpip, runuv and runpython subcommands
Browse files Browse the repository at this point in the history
  • Loading branch information
robinvandernoord committed Mar 4, 2024
1 parent 9059709 commit e9b2df1
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 4 deletions.
38 changes: 37 additions & 1 deletion src/uvx/cli.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
"""This file builds the Typer cli."""

import os
import subprocess
import sys
from typing import Optional

import plumbum
import rich
import typer
from typer import Context

from .core import (
as_virtualenv,
ensure_local_folder,
format_bools,
install_package,
list_packages,
reinstall_package,
run_command,
uninstall_package,
uv,
virtualenv,
)
from .metadata import Metadata, read_metadata

Expand Down Expand Up @@ -44,7 +54,6 @@ def list_short(name: str, metadata: Optional[Metadata]):


def list_normal(name: str, metadata: Optional[Metadata], verbose: bool = False):

if not metadata:
print("-", name)
rich.print(TAB, "[red]Missing metadata [/red]")
Expand Down Expand Up @@ -97,6 +106,33 @@ def list_venvs(short: bool = False, verbose: bool = False, json: bool = False):

# run


@app.command(
context_settings={"allow_extra_args": True, "ignore_unknown_options": True}
)
def runuv(venv: str, ctx: Context):
with as_virtualenv(venv):
run_command("uv", *ctx.args)


@app.command(
context_settings={"allow_extra_args": True, "ignore_unknown_options": True}
)
def runpip(venv: str, ctx: Context):
with as_virtualenv(venv):
plumbum.local["uv"]("pip", "install", "pip")
run_command("pip", *ctx.args)


@app.command(
context_settings={"allow_extra_args": True, "ignore_unknown_options": True}
)
def runpython(venv: str, ctx: Context):
with as_virtualenv(venv) as venv_path:
python = venv_path / "bin" / "python"
subprocess.run([python, *ctx.args])


# upgrade

# self-upgrade (uv and uvx)
Expand Down
28 changes: 28 additions & 0 deletions src/uvx/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,19 @@ def virtualenv(virtualenv_dir: Path | str) -> typing.Generator[Path, None, None]
local.python = old_python


@contextmanager
def as_virtualenv(venv_name: str) -> typing.Generator[Path, None, None]:
"""
External variant of the 'virtualenv' context manager above.
This variant takes in a venv name instead of a whole path.
"""
workdir = ensure_local_folder()
venv_path = workdir / "venvs" / venv_name
with virtualenv(venv_path):
yield venv_path


@contextmanager
def exit_on_pb_error() -> typing.Generator[None, None, None]:
"""Pass the plumbum error to the stderr and quit."""
Expand Down Expand Up @@ -367,9 +380,24 @@ def create_venv(name: str, python: Optional[str] = None, force: bool = False) ->


def list_packages() -> typing.Generator[tuple[str, Metadata | None], None, None]:
"""
Iterate through all uvx venvs and load the metadata files one-by-one.
"""
workdir = ensure_local_folder()

for subdir in workdir.glob("venvs/*"):
metadata = read_metadata(subdir)

yield subdir.name, metadata


def run_command(command: str, *args: str):
"""
Run a command via plumbum without raising an error on exception.
"""
# retcode = None makes the command not raise an exception on error:
exit_code, stdout, stderr = plumbum.local[command][args].run(retcode=None)

print(stdout)
print(stderr, file=sys.stderr)
return exit_code
3 changes: 0 additions & 3 deletions src/uvx/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,3 @@ def read_metadata(venv: Path) -> Metadata | None:

with metafile.open("rb") as f:
return typing.cast(Metadata, quickle_dec.loads(f.read()))


def get_metadata(): ...

0 comments on commit e9b2df1

Please sign in to comment.