Skip to content

Commit

Permalink
Add minimal Python API and task runner (#5903)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisrodrigue committed Dec 17, 2024
1 parent 5c3dafc commit ea4d848
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 0 deletions.
5 changes: 5 additions & 0 deletions python/uv/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@
import os

if os.environ.get("UV_PREVIEW"):
from ._api import uv
from ._build_backend import *
from ._tasks import run_tasks, task
from ._find_uv import find_uv_bin

if os.environ.get("UV_PREVIEW"):
__all__ = [
"uv",
"task",
"run_tasks",
"find_uv_bin",
# PEP 517 hook `build_sdist`.
"build_sdist",
Expand Down
8 changes: 8 additions & 0 deletions python/uv/_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
def uv(args: "str") -> int:
"""Execute `uv` with the given arguments."""
import shlex
import subprocess

from ._find_uv import find_uv_bin

return subprocess.run([find_uv_bin()] + shlex.split(args)).returncode
51 changes: 51 additions & 0 deletions python/uv/_tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
tasks = {}


def task(needs: "str | None" = None):
"""Define a task and optionally add task dependencies to the uv-managed project."""

if callable(needs):
return task()(needs)

def decorator(func):
import functools

@functools.wraps(func)
def wrapper(*args, **kwargs):
if needs:
from ._api import uv

uv(f"add {needs}")
return func(*args, **kwargs)

tasks[wrapper.__name__] = wrapper
return wrapper

return decorator


def run_tasks() -> None:
"""Run tasks from an autogenerated CLI."""
import argparse
import inspect

parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest="task")

for name, func in tasks.items():
docstring = func.__doc__
subparser = subparsers.add_parser(name, help=docstring, description=docstring)
for param in inspect.signature(func).parameters.values():
if param.default == param.empty:
subparser.add_argument(param.name, type=param.annotation)
else:
subparser.add_argument(
f"--{param.name}", type=param.annotation, default=param.default
)

if (args := parser.parse_args()).task:
func = tasks[args.task]
kwargs = {k: v for k, v in vars(args).items() if k != "task"}
func(**kwargs)
else:
parser.print_help()

0 comments on commit ea4d848

Please sign in to comment.